Notes

Iterables and Iterators

Edit on GitHub

JavaScript
2 minutes

Iterators

The iterator pattern is when you consume the values of a data source (could be a database, could be an array) one by one.

  • You get the next value by calling .next()
  • Iterables must have a property with a @@iterator key, which is available with constant Symbol.iterator
  • [Symbol.iterator] is a zero arguments function that returns an object conforming to the iterator protocol
  • An iterator result is an object with two properties on it: value and done. When the result becomes { value: undefined, done: true }, you have iterated over every value in the iterable. There’s nothing left to iterate over at this point.

Iterables

  • An iterable is something that can be iterated over
  • Built-in iterables are: String, Array, TypedArray, Map, Set and array-like objects (arguments or NodeList). But NOT Object. But you can create your own iterable object by implementing a .next() method for it

for…of

the for...of statement creates a loop iterating over built-in and user-defined iterable objects.

1for (variable of iterable) {
2  // do something
3}

You can use declare the variable with either var, let or const

1const iterable = [10, 20, 30];
2
3for (let value of iterable) {
4  value += 1;
5  console.log(value);
6}
7// 11
8// 21
9// 31

Creating custom iterators

The Object is not iterable, which is unfortunate because that’s the one we use the most, we build our own objects.

 1// Objects are not iterable..
 2var myObj = {
 3  a: 1,
 4  b: 2,
 5  c: 3
 6}
 7
 8for (let i of myObj) {
 9  console.log(i) // TypeError: myObj is not iterable
10}

But, we can define our own iterators by implementing the iterator protocol, i.e. implementing a next() method that returns at least the following two properties: value and done

 1var mySecondObj = {
 2  a: 1,
 3  b: 2,
 4  c: 3,
 5  [Symbol.iterator]: function(){ // the @@iterator property saved as the constant [Symbol.iterator]
 6    let keys = Object.keys(this)
 7    let index = 0
 8    return {
 9      next: () => (index < keys.length) ? // defining our own 'next' function to implement 'iterator protocol'
10      { done: false, value: this[keys[index++]]} :
11      { done: true, value: undefined}
12    }
13  }
14}
15console.log([...mySecondObj]) // [ 1, 2, 3 ]

Generators and Iterators