To understand the concept of iterator in Javascript, it is important to memorize the following three protocal:

1. Mark an object iterable

To mark an object iterable, you need to add a Symbol.iterator property to it:

varobj={};obj[Symbol.iterator]=function(){returniteratorObject;}

The Symbol.iterator part looks really odd if you don't know what Symbol is all about. One way to think about it is to see it as metadata that describes the hidden behaviors of an object. When an object is marked with the iterator symbol, it means you can loop through it like an array.

2. Return an iterator object

The code snippet above returns an iterator object. An iterator object needs to have a next method which is a function that returns an iterator result object:

iteratorObject={next:function(){returniteratorResultObj;}}

3. Return an iterator result object

Finally, I mean finally we can return some real values rather than wrappers that conforms to the iterable and iterator protocal.The iterator result object has to have two properties, one named value and the other named done.

iteratorResultObj={value:...,done:...// either true or false
}

As long as an object has the three traits explained above, it is iterable and can be used in a for...of loop or being spreaded [...myObj].

Putting it all together

varobj={};obj[Symbol.iterator]=function(){// mark an object as iterable
vari=1;return{// this is the iterator object
next:function(){returni<5?{// this is the iterator result object
value:i++,done:false}:{done:true}// when the iterator reaches the end, value = undefined and done = true
}}}variter=obj[Symbol.iterator]();console.log('value: '+iter.next().value);console.log('value: '+iter.next().value);console.log('value: '+iter.next().value);console.log('value: '+iter.next().value);console.log('done: '+iter.next().done);// the code above is equivalent of the following loop
for(varjofobj){console.log(j);}

Bonus

To use ES6 syntax and define an iterator within a class:

classMyArray{constructor(...items){this.items=items;}[Symbol.iterator](){letpos=0;letdata=this.items;// the value of `this` changes to undefined inside the next() function below, thus, we need to store it in a variable first
return{next:()=>{returnpos<data.length?{value:data[pos++],done:false}:{done:true}}}}}letarr=newMyArray(1,2,3)for(constiofarr){console.log(i);}