

Iterators and Generators in ES6 JavaScript
source link: https://www.tuicool.com/articles/hit/aiuIJrq
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

For an object to become an iterator it needs to know how to access values in a collection and keeping track of its position in the list. This is achieved by an object implementing a next
method and returning the next value in the sequence. This method should return an object containing two properties value
and done
. It must have the [Symbol.iterator]
as well as this is key to using JavaScripts for..of
loop.
Photo by Sunyu on Unsplash
Build your first iterator
function tenMultiplesOfThree(){ let start = 1; const multiple = 3; return { next: function() { if (start <= 10) { const product = multiple * start; start++; return { value: product, done: false }; } return { done: true }; } }; } let iterator = { [Symbol.iterator] : tenMultiplesOfThree }
Below is a for..of
using the above iterator. Without the [Symbol.iterator]
the for loop will not work.
for(let number of iterator){ console.log(number); } // -> 3, 6, 9, 12, 15, 18, 21, 24, 27, 30
Built-in iterators
String
, Array
, TypedArray
, Map
and Set
implement the Symbol.iterator method on their prototype. It is also possible to iterate a collection of DOM elements like a NodeList
.
for(let letter of "abc") { console.log(letter); } // -> "a" "b" "c"
Generators
You might be looking at the first code example and thinking it is pretty verbose and got some boiler code. ES6 has got some syntax sugar to help make this all look clean and succinct.
An example below of a generator:
function* firstTenMultiples(multiple = 3) { let start = 1; while(start <= 10){ yield multiple * start; start++; } } console.log(firstTenMultiples().next()); let iteratorGen = { [Symbol.iterator]: firstTenMultiples } for(let number of iteratorGen) { console.log(number); } // -> 3, 6, 9, 12, 15, 18, 21, 24, 27, 30
The key features to defining a generator are function*
. Yield essentially pauses the execution of the function body when it is reached until the next call is made. In the above example you can see by calling the firstTenMultiples
function we have access to next
method which returns value
and iterator state done
. This is the same as defining our own iterator except its more concise and easy to read.
I feel the asterisk makes this a bit awkward, in terms of remembering to use it and its position on function
. I’m sure this is new syntax we will get used to.
function* firstTenMultiples(multiple = 3) { let start = 1; while(start <= 10){ yield multiple * start; start++; } } let multiplesOfFour = firstTenMultiples(4); for(let number of multiplesOfFour) { console.log(number); } // -> 4, 8, 12, 16, 20, 24, 28, 32, 36, 40
From the above you can see I did not need to assign the generator function to [Symbol.iterator]
for for..of
loop to work. Inspecting the called result of firstTenMultiples(4)
you can see on the __proto__
it does have [Symbol.iterator]
implemented. This confirms calling a generator function returns a generator object which is iterable .
Generator finished
function* returnExample(){ yield "hello"; return "world"; yield "not reached" } const gen = returnExample(); console.log(gen.next()) // => { value: "hello", done: false } console.log(gen.next()) // => { value: "world", done: true } console.log(gen.next()) // => { value: undefined, done: true }
In the above example return
ends the generator and sets the done state to true. Anything after that is not reached.
Delegate to another generator
function* countToThree(){ yield 1; yield 2; yield 3; } function* firstTenMultiples(multiple = 3) { let start = 1; yield* countToThree(); while(start <= 10){ yield multiple * start; start++; } } let multiplesOfFour = firstTenMultiples(4); for(let number of multiplesOfFour) { console.log(number); } // -> 1, 2, 3, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40
In the above example firstTenMultiples
uses yield*
to delegate to countToThree
generator function. This result in listing one to three first then multiples of four.
Pass in a value via next()
method
function* firstTenMultiples(multiple = 3) { let start = 1; while(start <= 10){ let reset = yield multiple * start; start++; if(reset) start = 1; } } let multiplesOfFour = firstTenMultiples(4); console.log(multiplesOfFour.next().value); // 4 console.log(multiplesOfFour.next().value); // 8 console.log(multiplesOfFour.next().value); // 12 console.log(multiplesOfFour.next(true).value); // 4 (reset to start from beginning) console.log(multiplesOfFour.next().value); // 8 console.log(multiplesOfFour.next().value); // 12
In the above example, the first parameter is used to reset the generator to start from the beginning. The last yield
expression which paused the generator will use the parameter value as the result. Assigning yield
to the variable reset
, the value is undefined
until a parameter is passed in, causing reset
value to become true
in this case.
Destructing values from iterator
const [a, b, c] = firstTenMultiples(5); // -> a = 5, b = 10, c = 15
Spread values from iterator
const multiplesOfSix = [...firstTenMultiples(6)]; // -> [6, 12, 18, 24, 30, 36, 42, 48, 54, 60]
Hopefully, you find all these examples useful to getting started with iterators and generators.
References:
Recommend
-
163
Professionals | Community Groups Programs | Google Developers
-
202
Unless otherwise noted, changes described below apply to the newest Chrome Beta channel release for Android, Chrome OS, Linux, Mac, and Windows. Dynamic module...
-
29
This post concludes the series Symbols, Iterables, Iterators and Generators in JavaScript. It would be a whirlwind tour of generator fun...
-
26
All you need to know about JavaScript Iterators and Generators
-
13
a fizz-buzz problem Job interviews sometimes contain simple programming tasks. Often called “fizz-buzz problems,” the usual purpose is to quickly weed out hopefuls who can’t actually program anything. Here’s an example, some...
-
11
Use Iterators, Generators, and Generator ExpressionsBy Rahul Agarwal 28 November 2020
-
8
Explore Iterators and Generators in JavaScriptGet to know the applications of Iterators and Generators in JavaScript
-
7
为了方便集合数据的遍历,在ES6中引入了一个iteration的概念。为我们提供了更加方便的数据遍历的手段。 一起来学习一下吧。 什么是iteration iteration也称为遍历,就是像数据库的游标一样,一步一步的遍历集合或者对象的数据。 ...
-
8
Async iterators and generatorsPosted 18 April 2017 Streaming fetches are supported in Chrome, Edge, and Safari, and they look a little like this: async function getResponseSize(url) { const response = await fetc...
-
12
Understanding Generators, Iterators, and Iterator Helpers in JavaScript Nov 23, 2023 •
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK