An iterator is a structured pattern for extracting data from a source, one at a time. The use of iterators can greatly simplify data manipulation, so ES6 has added this iterator feature to JS. New array methods and new collection types (such as sets and maps) rely on iterators. This new feature is essential for efficient data processing, and iterators are present in many other language features: new for-of loops, expansion operators (…) Even asynchronous programming can use iterators.

Today I will introduce iterators from the following aspects:

  • What is an iterator?
  • Implement iterators based on protocol
  • Application of iterators

The reading time for this article is expected to be 6 minutes.

Iterators

An iterator is an ordered, continuous, pull-based organization that consumes data and controls behavior one step at a time. To put it simply, we iterate over an iterable, not returning all the data at once, but calling related methods to return it in fractions.

An iterator is an object that has a next function that returns an object with value and done attributes, where value refers to the value defined by the current next function in the iteration sequence.

Iteration protocols of ES6 are divided into iterator protocol and iterable protocol. Iterators are implemented based on these two protocols.

Iterator protocol: The Iterator protocol defines a standard method for producing sequences of values. This object is an iterator as long as we implement the appropriate next function. A pointer that iterates over data structure elements, similar to a cursor in a database.

Iterable protocol: Once the iterable protocol is supported, it means that the object can be iterated with for-of, which can be used to define or customize the iterative behavior of JS objects. Common built-in types such as Array & Map support the iterable protocol. The object must implement the @@iterator method, which means that the object must have a property with the @@iterator key that can be accessed through the constant symbol. iterator.

The following figure shows the iterable protocol implemented by the Arrays,Maps, and Strings data types. We can display iterator data using for-of and expansion syntax.

Implement iterators based on protocol

Iterator protocol

The following code shows the implementation based on the iterative protocol:

let obj = {
 array: [1, 2, 3, 4, 5],
 nextIndex: 0,
 next: function() {
         return this.nextIndex < this.array.length ? 
         {value: this.array[this.nextIndex++], done: false}, {done: true}}}; console.log(obj.next().value); console.log(obj.next().value); console.log(obj.next().value); console.log(obj.next().value); console.log(obj.next().value); console.log(obj.next().done);Copy the code

The above code will be printed

One, two, three, four, fivetrueCopy the code

The next method of the above code can also be rewritten to make it clearer:

if(this.nextIndex < this.array.length) {
  this.nextIndex++;
  return { value: this.array[this.nextIndex], done: false}}else {
  return { done: true}}Copy the code

As we can see, the implementation of the next method, if there is a new element, returns the current element and increments the identification of the current element position by 1, or {done: true} if there is no element.

Iterable protocol

According to the iterable protocol, objects need to provide @@iterator methods; That is, it must use the Symbol. Iterator Symbol as the property key. The @@iterator method must return an iterator object. The code implementation is as follows:

let obj = {
  array: [1, 2, 3, 4, 5],
  nextIndex: 0,
  [Symbol.iterator]: function() {return {
     array: this.array,
     nextIndex: this.nextIndex,
     next: function() {return this.nextIndex < this.array.length ?
          {value: this.array[this.nextIndex++], done: false}, {done: true}; }}}};let iterable = obj[Symbol.iterator]()
console.log(iterable.next().value);
console.log(iterable.next().value);
console.log(iterable.next().value);
console.log(iterable.next().value);
console.log(iterable.next().value);
console.log(iterable.next().done);Copy the code

The above code will be printed

One, two, three, four, fivetrueCopy the code

In the above code, we implemented a custom iterator that made jS-BASED scoping and closure features easy to implement. The Arrays,Maps,Strings data types implement the iterable protocol, and their __proto__ prototype chain points to the built-in Symbol. Iterator method, which saves us the time of handwritten code, as shown in the following code:

const arr = [1, 2];
const iterator = arr[Symbol.iterator](); // returns you an iterator
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())Copy the code

The above code will print:

{ value: 1, done: false }
{ value: 2, done: false }
{ value: undefined, done: true }Copy the code

We can use for-of to expand the syntactic iteration array in the following example:

const arr = [1, 2];
for(var v of arr){ console.log(v); } //outputs 1 //outputs 2 console.log([...arr]); / / outputs [1, 2];Copy the code

Obj objects do not implement the iterable protocol. How do we iterate over OBJ objects? An iterator that implements obj looks like this:

var obj={
    a:1,
    b:2,
    c:3,
    [Symbol.iterator]:function() { var keys=Object.keys(this); //object.vulues(this) var index=0;return{
            next:()=>
            (index<keys.length)?
            {value: this[keys[index++]], done:false}, {done: true,value:undefined} } } }; console.log([...obj]); / / outputs [1, 2, 3]Copy the code

Iterator application

Fibonacci numbers

The Fibonacci sequence, also known as the Golden section sequence, was introduced by mathematician Leonardoda Fibonacci as an example of rabbit reproduction. It refers to a sequence of numbers: 1, 1, 2, 3, 5, 8, 13, 21, 34… In mathematics, Fibonacci sequence in the following definition of recursive method: F (1) = 1, F (2) = 1, F (n) = F (n – 1) + F (n – 2) (n > = 3, n ∈ n *).

We can use an iterator to produce a Fibonacci sequence of up to 100 as an example:

let Fib= {
    [Symbol.iterator](){
        let n1=1;
        let n2=1;
        let max=100;
        return {
            next() {let current=n2;
                n2=n1;
                n1=n1+current;
                if(current<max){
                    return {value: current, done: false}}else{
                    return { done: true}
                }

            }
        }
    }
}
console.log([...Fib]);
//outputs [ 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 ]Copy the code

Simulated task queue

Sometimes we need to execute tasks in a queue and execute them in batches. We can use iterators to simulate this. Example code is as follows:

let tasks={
    actions:[],
    [Symbol.iterator](){
        let steps=this.actions.slice();
        return {
            [Symbol.iterator]() {returnthis; }, next(... args){if(steps.length>0){
                    letres=steps.shift()(... args);return {value:res,done:false};
                }
                else{
                    return {done:true}}},return(v){
                steps.length=0;
                return {value:v,done:true}; }}; }}; tasks.actions.push(function step1(x) {
        console.log("step 1:",x);
        return x*2;
    },
    function step2(x,y) {
        console.log("step 2:",x,y);
        return x+(y*2);
    },
    function step3(x,y,z) {
        console.log("step 3:",x,y,z);
        return(x*y)+z; });letit=tasks[Symbol.iterator](); console.log(it.next(10)); The console. The log (it. Next (20, 50)); The console. The log (it. Next (20,50,120)); console.log(it.next());Copy the code

Output from the above code:

step 1: 10
{ value: 20, done: false }
step 2: 20 50
{ value: 120, done: false }
step 3: 20 50 120
{ value: 1120, done: false }
{ done: true }Copy the code

From the above code, we can see that an iterator is not just an iteration of data, but also a pattern to organize related functionality. (Note: This example comes from JavaScript you Don’t Know, vol. 2)

section

We control the interruption and continuation of functions at will, which enrichis our thinking of problem solving, makes our code look more engineering and structured, and improves the readability and comprehensibility of the code.

ES6 Basics Let and scope

【ES6 basics 】 Const introduction

ES6 Basics Default value

【ES6 分 】 Spread syntax

【ES6 Basics 】 Destructuring Assignment

【ES6 basics 】 Arrow functions

【ES6 Basics 】 Template String

【ES6 foundation 】Set and WeakSet

【ES6 foundation 】Map and WeakMap

【ES6 basics 】Symbol Description: unique values

【ES6 basics 】 New methods of Object

【 Data Structure Basics 】 Stack Introduction (using ES6)

Introduction to Queues (using ES6)

More exciting content, please pay attention to the wechat “front-end talent” public number!