Iterables in JavaScript

Iterables in JavaScript

What are Iterables?

  • Iterables are data structures on which for...of loop can be used, Loop-ables,
  • JavaScript provides such data structures like array, map, sets, strings etc,
  • There's a method (function) named [Symbol.iterator] which enables looping over the data structure, and also defines how the looping will work on the structure,
  • The beauty is: you can add this method on data structure and make it loop-able/iterable

Iterables in JavaScript

[Symbol.iterator]:

  • The name of the property is [Symbol.iterator] (along with brackets []),
  • Its a function (method), that returns an object, this object called "iterator",
  • the object "iterator" needs to have a method in it named: "next () {}",
  • the method should return an object which should be exactly like this:
    {done:false, value:"value"}
    OR
    { done: true };
  • when done: true is returned the loop stops
[Symbol.iterator] = function() {

  // for..of works only with the 
  // iterator object below, asking it for next values
  return {
    current: 0,
    last: 10,

    // next() is called on each iteration 
    // by the for..of loop
    next() {
      // it should return the value 
      // as an object {done:.., value :...}
      if (this.current <= this.last) {
        return { done: false, value: this.current++ };
      } else {
        return { done: true };
      }
    }
  };
};

Iterables in JavaScript

Example:

Making a simple object iterable:

const range = {
  from: 1,
  to: 5,
  
  [Symbol.iterator]() {
    return {
      current: this.from,
      last: this.to,
      
      next() {
        if (this.current <= this.last) {
          return { done: false, value: this.current++ };
        } else {
          return { done: true };
        }
      }
    };
  }
};

// now it works!
for (const num of range) {
  console.log({num}); // 1, then 2, 3, 4, 5
}
const range = {
  from: 1,
  to: 5,
}

// won't work!
for (const num of range) {
  console.log({num});
}

Iterables in JavaScript

Example:

  • When the loop runs, first of all it calls the "[Symbol.iterator]" method which returns the iterator object,
  • the iterator object has the next() method
  • in every loop, the loop calls the next method, and gives the value from the {done, value} object returned by next() method,
  • the loop ends when next method return {done: true} object
// Different way of writing
const range = {
  from: 1,
  to: 5,

  [Symbol.iterator]() {
    this.current = this.from;
    return this;
  },

  next() {
    if (this.current <= this.to) {
      return { done: false, value: this.current++ };
    } else {
      return { done: true };
    }
  }
};

for (let num of range) {
  alert(num); // 1, then 2, 3, 4, 5
}

Iterables in JavaScript

Example:

  • understand the for loop on the iterable
// Different way of writing
const range = {
  from: 1,
  to: 5,

  [Symbol.iterator]() {
    this.current = this.from;
    return this;
  },

  next() {
    if (this.current <= this.to) {
      return { done: false, value: this.current++ };
    } else {
      return { done: true };
    }
  }
};

// Read the loop as:
for (let num = range[Symbol.iterator]().next()) {
  alert(num); // 1, then 2, 3, 4, 5
}

Iterables in JavaScript

Calling an iterator explicitly:

  • On iterable structures, you can directly call the [Symbol.iterator]() method,
  • calling the method will return you the iterator object, which has the next() method on it,
  • we can call the next method to get the next value in the loop
let str = "Hello";

// does the same as
// for (let char of str) alert(char);

let iterator = str[Symbol.iterator]();

while (true) {
  let result = iterator.next();
  if (result.done) break;
  else console.log(result.value);
}

Iterables in JavaScript

Iterables and array-likes:

  • Two official terms look similar, but are very different,
  • Iterables are objects that implement the [Symbol.iterator] method, as described above.

Array-likes:

  • Array-likes are objects that have indexes and length, so they look like arrays,
  • But array-likes are not iterable/loop-able
  • But an iterable may be not array-like. And vice versa an array-like may be not iterable,
const arrayLike = {
  0: "Hello",
  1: "World",
  length: 2
};

Iterables in JavaScript

Array.from

  • There’s a universal method Array.from
  • takes an iterable or array-like value and makes a “real” Array from it.
  • Then we can call array methods on it.
let arrayLike = {
  0: "Hello",
  1: "World",
  length: 2
};

let arr = Array.from(arrayLike);
alert(arr.pop());