Tuesday, September 22, 2020

Iterators are basically all objects that know hoe to access values in a collection one at a time, an array for example in such an iterator in which you can loop through it, it has a collection of objects and it knows how to output them one after another.

Now in ES6 you can also create your own objects with your own iterator logic.

let numbersArray = [1,2,3,4];

Arrays in javascript are iterable if it has a certain well know Symbol. That’s JavaScript way of knowing that you actually can loop over. (Symbols)

console.log(typeof numbersArray[Symbol.iterator]); // “function”

Here we have an iterator which is a function that is used when we loop through an array.

Now if we print the iterator function:

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

console.log(iterator); // [object Array Iterator]

to be specific this iterator object is an object with only one method, the next method.

console.log(iterator.next()); // [object Object] {
  			                       //  done: false,
                  		               //  value: 1
                                               // }

now if you Start over and run next 5 times:

console.log(iterator.next()); 
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

we get:

[object Object] {
  done: false,
  value: 1
}
[object Object] {
  done: false,
  value: 2
}
[object Object] {
  done: false,
  value: 3
}
[object Object] {
  done: false,
  value: 4
}
[object Object] {
  done: true,
  value: undefined
}

You can see that by calling next() multiple times we kind of seem to be stepping through the array items. Notice that the fifth time we run next the value is undefined since we ran out of items in the collection and reaching the first undefined value.

[vc_custom_heading text=”Using Iterators in your own Objects “]

You can make any object iterable, all you have to use is implement the Symbol.iterator we saw earlier. We also can override the behavior of our built in objects as Arrays by overriding its iterator that is simply a function that returns an object with a next function that at the end returns an object with done and value properties.

let numbersArray = [1,2,3,4];


numbersArray[Symbol.iterator] = function() {
  let dummyValue = 1000;
  return {
    next: function() {
      return {
        done: false,
        value: dummyValue
      }
    }
  }
}

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

console.log(iterator.next()); 
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

This Prints:

[object Object] {
  done: false,
  value: 1000
}
[object Object] {
  done: false,
  value: 1000
}
[object Object] {
  done: false,
  value: 1000
}
[object Object] {
  done: false,
  value: 1000
}
[object Object] {
  done: false,
  value: 1000
}

In order to make an object iterable you need to implement Symbol.iterator as we described earlier:

let person = {
  name: 'Carlos',
  familyMembers: ['Lorena', 'Sofia', 'Lorein'],
  [Symbol.iterator]: function () {
    let i = 0;
    let familyMembers = this.familyMembers;
    return {
      next: function () {
        let value = familyMembers[i];
        i++;
        return {
          done: i > familyMembers.length ? true : false,
          value: value
        }
      }
    }
  }
}

for (let fMember of person) {
  console.log(fMember);
}

By providing   [Symbol.iterator] we are telling javascript this object is iterable, all we needed to do were to define our logic for the iterator and its next function.

Here I just made the person object iterable and its up to the us to define what iterating over our objects mean and how should iteration behave