Iteration

keep in mind...

  1. for/of loops are not for objects!
  2. use break to stop the loop
  3. now possible to create custom iterators
for/of loopfor/in loopforEach()stopping loops[Symbol.iterator]

Compared to the old for (var i = 0; i < array.length; i++){}, the newer forms of Javascript loops make code a lot simpler.

for/of loop

For/of loops are the new default for most folks, and for good reason. They can be used to iterate over things like arrays, sets, maps, strings, and iterables, but notably not over objects. Array example:

edit and re-run!
const cars = ['chevy', 'prius', 'jeep'];

for (const car of cars) {
  console.log(car);
};
chevy
prius
jeep

Maps use key, value pairs, and you can get at the keys and values using an array inside of your for/of loop:

edit and re-run!
const kids = new Map([['jack', 'boy'], ['suzy', 'girl']]);

for (const [key, value] of kids) {
  console.log(`key: ${key},   value: ${value}`);
}
key: jack, value: boy
key: suzy, value: girl

Sets are a little like an array, but the elements must be unique - so duplicates are discarded.

edit and re-run!
const kids = new Set(['jack', 'suzy', 'betty', 'jack']);

for (const kid of kids) {
  console.log(kid);
}
jack
suzy
betty

Strings can be iterated too!

edit and re-run!
const name = 'Antonio';

for (const letter of name) {
  console.log(letter);
}
A
n
t
o
n
i
o

for/in loop

For/in loops are just for objects - so don't confuse the "in" with f"! You can iterate over the values for keys like so:

edit and re-run!
const kid = {name: 'Billy', 'grade': 4, 'sport': 'tennis'};

for (const key in kid) {
  console.log(kid[key]);
} 
Billy
4
tennis

forEach()

for/each loops only work with arrays, and you cannot stop execution by continue or break statements. They do make code easy to read.

edit and re-run!
const cars = ['chevy', 'prius', 'jeep'];

cars.forEach(function(car){
  console.log(car);
});
  
chevy
prius
jeep

stopping loops

So what if you want to stop execution of your loop based on some condition or value? With for/of and for/in loops (however not forEach ones), you can use:

break

breaks or stops the loop (read more @ mdn).

edit and re-run!
const cars = ['chevy', 'prius', 'jeep'];

for (const car of cars) {
  if (car == 'prius') break;
  console.log(car);
};
chevy

continue

breaks one iteration (in the loop), going to next iteration. (read more @ mdn).

edit and re-run!
const cars = ['chevy', 'prius', 'jeep'];

for (const car of cars) {
  if (car == 'prius') continue;
  console.log(car);
};
  
chevy
jeep

return

stops loop completely, also exits any parent function and executes no more code

edit and re-run!
const getCars = () => {

const cars = ['chevy', 'prius', 'jeep'];

  for (const car of cars) {
    if (car == 'prius') return;
    console.log(car);
  };

console.log('end of the getCars function');
};
getCars();  
chevy

[Symbol.iterator]

You may not realize it, but under the hood, for...of loops are actually using Symbol.iterator already. One thing that's cool is the 'done' attribute, saving you the trouble of figuring out manually when your loop is done, & you need something else to happen. It also keeps track of the iteration number for you, which can be helpful if you've been doing it manually.

Here is a simple array, and resulting iterator, looking "under the hood"...

edit and re-run!
var arr = [1, 2, 3];
var iterator = arr[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
{"value":1,"done":false}
{"value":2,"done":false}
{"value":3,"done":false}
{"done":true}

This new ES6 concept allows you to roll your own iterators as well, and create a custom and structured iterator in which you choose which values to return for each iteration. If you're wondering why the heck you'd want to go to that trouble... here a few scenarios where it makes sense.

to chunk large data

This wouldn't make a lot of sense with just 10 posts, but if you had a lot of posts, it is an easy way to paginate or load in chunks, where the iterator keeps track of what number you're on.

edit and re-run!
let posts = ['post 1', 'post 2', 'post 3', 'post 4', 'post 5', 'post 6', 'post 7', 'post 8', 'post 9', 'post 10'];
let it = posts[Symbol.iterator]();

function loadPosts(iterable, count) {
  for (let i = 0; i < count; i++) {
    console.log( iterable.next().value );
  }
}

loadPosts(it, 5);
loadPosts(it, 5);
post 1
post 2
post 3
post 4
post 5
post 6
post 7
post 8
post 9
post 10

Perform cool regex actions

As somebody who does a lot of regexy stuff in the various e-learning apps I've done, I can see why doing this in your iterator would be great, and keep things really clean.

edit and re-run!
let Sentence = function(str) {
  this._str = str;
}
Sentence.prototype[Symbol.iterator]  = function() {
  var re = /\w+/g;
  var str = this._str;
  return {
  next: function() {
    var match = re.exec(str);
    if (match) {
      return {value: match[0].toLowerCase(), done: false};
    }
    return {value: undefined, done: true};
    }
  }
};
var words = new Sentence('Hey have an AWESOME day!');

for (let word of words) {
  console.log(word);
}
 
hey
have
an
awesome
day

with a generator function

Generator functions (read more here) look pretty foreign to anybody used to writing pre es6 Javascript.

edit and re-run!
function* generateMe() {
  yield 'i';
  yield 'love';
  yield 'programming';
};
const gen = generateMe();

console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
{"value":"i","done":false}
{"value":"love","done":false}
{"value":"programming","done":false}
{"done":true}

The magic of generators is that they can be paused as they are running, and return multiple values as execution pauses and resumes. Sounds cool but what would that actually look like? One example is an infinite loop - which would normally crash your browser! Since you pause after each next() statement, that isn't a problem with a generator.

edit and re-run!
function *infiniteLoop() {
  let start = 0;
  let val = 1; 
  while(val > start) {
    yield val++;
  }
}
let loop = infiniteLoop();
console.log(loop.next());
console.log(loop.next());
console.log(loop.next());
console.log(loop.next());
{"value":1,"done":false}
{"value":2,"done":false}
{"value":3,"done":false}
{"value":4,"done":false}

You can combine the spread operator (...) with a generator to produce a quick array.

edit and re-run!
function* generateMe() {
  yield 'i';
  yield 'love';
  yield 'programming';
};
const gen = generateMe();
console.log([...gen]);
i,love,programming

A generator can be used here to simplify the Sentences iterator you created above.

edit and re-run!
let Sentence = function(str) {
  this._str = str;
}
Sentence.prototype[Symbol.iterator] = function*() {
  var re = /\w+/g;
  var str = this._str;
  var match;
  while (match = re.exec(str)) {
    yield match[0].toLowerCase();
  }
};
var words = new Sentence('Hey have an SUPER day!');

for (let word of words) {
  console.log(word);
}
 
hey
have
an
super
day

Review of [Symbol.iterator] & Generators

A great summary is found here at code.tutsplus.com

Iterators and generators come in handy when you want to process a collection incrementally. You gain efficiency by keeping track of the state of the collection instead of all of the items in the collection. Items in the collection are evaluated one at a time, and the evaluation of the rest of the collection is delayed till later.

Iterators provide an efficient way to traverse and manipulate large lists. Generators provide an efficient way to build lists. You should try out these techniques when you would otherwise use a complex algorithm or implement parallel programming to optimize your code.

Research More...

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
  3. https://hacks.mozilla.org/2015/04/es6-in-depth-iterators-and-the-for-of-loop
  4. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
  5. https://stackabuse.com/es6-iterators-and-generators/
  6. https://vegibit.com/iterators-in-es6/
  7. https://javascript.info/iterable