What is an Iterator?

An object that satisfies the iterator protocol. Iterator protocol: The next method on an object is a no-argument function that returns an object with both done and value properties:

  • done(boolean) :
    • If the iterator has already passed through the iterated sequencetrue. At this momentvalueMay describe the return value of the iterator.
    • If the iterator can produce the next value in the sequencefalse. This is equivalent to withdoneAttributes are also not specified.
  • value: Any JavaScript value returned by the iterator.donefortrueWhen can be omitted.

ES5 implements a simple iterator:

function createIterator(items) { var i = 0; return { next: function() { var done = (i >= items.length); var value = ! done ? items[i++] : undefined; return { done: done, value: value }; }}; } var iterator = createIterator([1, 2, 3]); console.log(iterator.next()); // "{ value: 1, done: false }" console.log(iterator.next()); // "{ value: 2, done: false }" console.log(iterator.next()); // "{ value: 3, done: false }" console.log(iterator.next()); // "{value: undefined, done: true}" // Console. log(iterator.next()); // "{ value: undefined, done: true }"Copy the code

What is an Iterable?

An object that satisfies the iterable protocol is an iterable. Iterable protocol: The object’s [symbol. iterator] value is a no-parameter function that returns an iterator.

In ES6, all collection objects (Array, Set, and Map), as well as String and arguments, are iterable and have default iterators.

Iterables can be used in the following statements:

  • for… Of circulation
for (let value of ['a', 'b', 'c']) {
  console.log(value);
}
// "a"
// "b"
// "c"Copy the code
  • Extended operator
[...'abc']; // ["a", "b", "c"] console.log(... ['a', 'b', 'c']); // ["a", "b", "c"]Copy the code
  • yield*
function* gen() {
  yield* ['a', 'b', 'c'];
}

gen().next(); // { value: "a", done: false }Copy the code
  • Deconstruction assignment
let [a, b, c] = new Set(['a', 'b', 'c']);
a;   // 'a'Copy the code

understandfor… ofcycle

for… Of takes an Iterable, or a value that can be cast/wrapped into an Iterable (e.g. ‘ABC’). Throughout, for… Of gets the iterable’s [symbol.iterator]() and calls next() each time until the iterator returns the done attribute of the object as true, leaving the value unprocessed.

for… Example of the of loop:

var a = ["a","b","c","d","e"];

for (var val of a) {
    console.log( val );
}
// "a" "b" "c" "d" "e"Copy the code

Convert to the plain for loop example, equivalent to the above for… Of cycle:

var a = ["a","b","c","d","e"]; for (var val, ret, it = a[Symbol.iterator](); (ret = it.next()) && ! ret.done; ) { val = ret.value; console.log( val ); } // "a" "b" "c" "d" "e"Copy the code

Make iterators iterable

In the what is an iterator section, we define a simple function createIterator that generates iterators. However, the iterator generated by this function does not implement the iterable protocol, so it cannot be used in the for… Used in the grammar of. An iterable protocol can be implemented for this object, returning the iterator itself in the [symbol. iterator] function.

function createIterator(items) { var i = 0; return { next: function () { var done = (i >= items.length); var value = ! done ? items[i++] : undefined; return { done: done, value: value }; }, [Symbol.iterator]: function () { return this } }; } var iterator = createIterator([1, 2, 3]); console.log(... iterator)Copy the code

What is a Generator?

Generator function

A generator function is a function that returns a generator. Generator functions are indicated by an asterisk (*) placed after the function keyword and can use the new yield keyword.

function *aGeneratorfunction(){ yield 1 yield 2 yield 3 }; Var aGeneratorObject = aGeneratorfunction () / / Generator objects aGeneratorObject. The toString () / / "[object Generator]"Copy the code

Generator objects are both iterators and iterables

function *aGeneratorfunction(){ yield 1 yield 2 yield 3 }; Var aGeneratorObject = aGeneratorfunction() var ageneratorObject.next () {value: 1, done: false} aGeneratorObject.next() // {value: 2, done: false} aGeneratorObject.next() // {value: 3, done: false} aGeneratorObject.next() // {value: undefined, done: True} // [symbol.iterator] is a no-argument function that returns the generator object itself (which is an iterator), AGeneratorObject [symbol.iterator]() === aGeneratorObject // true // can be iterated var aGeneratorObject1 = aGeneratorfunction() [...aGeneratorObject1] // [1, 2, 3]Copy the code

Return in generator

The iteration ends when the done value of the object returned by traversal is true, and that value is not processed.

function *createIterator() {
  yield 1;
  return 42;
  yield 2;
}

let iterator = createIterator();
iterator.next();   // {value: 1, done: false}
iterator.next();   // {value: 42, done: true}
iterator.next();   // {value: undefined, done: true}Copy the code

The iteration ends when the done value is true and the iteration does not process that value. So iterating over this iterator does not deal with the value 42.

let iterator1 = createIterator(); console.log(... iterator); / / 1Copy the code

add[Symbol.iterator]makeObjectCan the iteration

According to the iterable protocol, add [symbol. iterator] to the prototype of Object. The value is a function that returns an Object with no arguments.

Object.prototype[Symbol.iterator] = function () { var i = 0 var items = Object.entries(this) return { next: function () { var done = (i >= items.length); var value = ! done ? items[i++] : undefined; return { done: done, value: value }; } } } var a = { name: 'Jimmy', age: 18, job: 'actor' } console.log(... a) // [ 'name', 'Jimmy' ] [ 'age', 18 ] [ 'job', 'actor' ]Copy the code

Simplify code with generators:

Object.prototype[Symbol.iterator] = function* () { for (const key in this) { if (this.hasOwnProperty(key)) { yield [key,  this[key]]; } } } var a = { name: 'Jimmy', age: 18, job: 'actor' } console.log(... a) // [ 'name', 'Jimmy' ] [ 'age', 18 ] [ 'job', 'actor' ]Copy the code

Generator delegateyield*

function* g1() { yield 1; yield 2; } function* g2() { yield* g1(); yield* [3, 4]; yield* "56"; yield* arguments; } var generator = g2(7, 8); console.log(... generator); // 1 2 3 4 "5" "6" 7 8Copy the code

One last example

Analyze the following code:

function* fibs() {
  var a = 0;
  var b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}

var [first, second, third, fourth, fifth, sixth] = fibs();
console.log(first, second, third, fourth, fifth, sixth);Copy the code

In this code, FIBS is a generator that generates an infinitely long Fibonacci sequence. [a, b] = [b, a+b] is a commutative assignment written using a deconstructed assignment (= assignment is evaluated from right to left, so a+b on the right is evaluated first). Write ES5 to generate a finitely long array as follows:

function fibs1(n) {
  var a = 0;
  var b = 1;
  var c = 0;
  var result = []
  for (var i = 0; i < n; i++) {
    result.push(a);
    c = a;
    a = b;
    b = c + b;
  }

  return result;
}

console.log(fibs1(6))   // [0, 1, 1, 2, 3, 5]Copy the code

The first code deconstructs the first six values from the fibs() iterator (generators are a subset of iterators) as follows:

function* fibs2(n) { var a = 0; var b = 1; for (var i = 0; i < n; i++) { yield a; [a, b] = [b, a + b]; } } console.log(... fibs2(6))Copy the code

Why use iterators, generators, and what are the benefits?

. Haven’t figured it out yet

Above, there are a lot of personal understanding of the part, welcome to correct (* ̄)  ̄)

Reference:

  • You don’t understand JS: ES6 and the future
  • Understanding ECMAScript 6: Chapter 8 Iterators and Generators
  • MDN: indicates an iterative protocol
  • MDN: iterator and generator
  • Complete understanding of Python iterators, iterators, and generators
  • ES6 (vi) : Destructuring