iterators
iterator & iterable
An iterator is an object with a next method that returns { done, value } tuples.
ES6 gives us a pattern for creating custom iterators and it has a similar implementation to Java Iterable or .NET IEnumerable. It has also built-in iterables: String, Array, TypedArray, Map and Set. An iterator object can be any object with a next() method.
Iterable is an object which has Symbol.iterator method inside.
Symbol is in turn an unique and immutable data type which can be used as an identifier for object properties — no equivalent in ES5.
1 // Symbol
2 let s1 = Symbol('abc');
3 let s2 = Symbol('abc');
4
5 console.log(s1 !== s2); // true
6 console.log(typeof s1); // 'symbol'
7
8 let obj = {};
9 obj[s1] = 'abc';
10 console.log(obj); // Object { Symbol(abc): 'abc' }
Let’s see a simple iterator written from scratch, which allows us to iterate through random numbers which are dynamically generated by next() method. A function returning iterable object take one argument (items) which is used to determine if the iterator should stop and returns done = true.
1 let random1_10 = function (items = 1) {
2 return {
3 [Symbol.iterator]() {
4 let cur = 0;
5 return {
6 next() {
7 let done = cur === items,
8 random = Math.floor(Math.random() * 10) + 1;
9 ++cur;
10 return {
11 done: done,
12 value: random
13 }
14 }
15 }
16 }
17 };
18 };
19
20 for (let n of random1_10(5)) {
21 console.log(n); // prints 5 random numbers
22 }
Every time for-of loop call next() method, an iterator generate a random number and returns it to the loop.
If the iterator returns done = true, you can omit value, so the result will be { done: true }
1 let random1_10 = function (items = 1) {
2 return {
3 [Symbol.iterator]() {
4 let cur = 0;
5 return {
6 next() {
7 if (cur === items) {
8 return {
9 done: true
10 }
11 }
12 ++cur;
13 return {
14 done: false,
15 value: Math.floor(Math.random() * 10) + 1
16 }
17 }
18 }
19 }
20 };
21 };
22
23 for (let n of random1_10(5)) {
24 console.log(n); // prints 5 random numbers
25 }
for-of loop
ES6 has a new loop — for-of. It works with iterables. Let’s look at his signature:
1 for (LET of ITERABLE) {
2 CODE BLOCK
3 }
It’s similar to for-in loop, which can be used to iterate through object properties (plain old Objects).
Arrays in ES6 are iterable by default, so we finally can use for-of for looping over the elements.
1 const arr = [1, 2, 3, 4, 5];
2
3 for (let item of arr) {
4 console.log(item); // 1
5 // 2
6 // 3
7 // 4
8 // 5
9 }
Inside the for-of loop, we can even use a break, continue and return.
1 const arr = [1, 2, 3, 4, 5];
2
3 for (let item of arr) {
4 if (item > 4) {
5 break;
6 }
7 if (0 !== item % 2) {
8 continue;
9 }
10 console.log(item); // 2
11 // 4
12 }