This is the 18th day of my participation in the August Challenge

πŸ“’ Hi, my name is Xiao Cheng. This article will take you through the iterators in ES6.

Found the problem

Before the iterator pattern was introduced in ES6, what were the problems with traditional iteration? Why add the iterator concept?

Let’s start with a couple of examples

let arr = ['small'.'cheng'.'ah']
Copy the code

This is a simple array, and if we want to get each item of it, we can do a for loop, or we can do a forEach loop, which is cool

The forEach loop was explained in the previous article, linked in the original article

It’s not a problem when it’s pure, right

Let’s look at the following example. Prints the given string as a single character

let str = '011010'
Copy the code

You can use for loops and for… In circulation

And so the problem arose

In both cases, our goal is to traverse, but we need to consider different ways to traverse

In the first code we iterate over an array, in the second we iterate over a string, and we do it differently, which means we tend to iterate differently for different data structures.

In JavaScript, the existing data structures for “collections” are Array and Object. In ES6, Map and Set have been added, and these data structures can also be combined. Faced with so many data structures, we can not use a unified traversal method to obtain the data, this is the problem!

Of course, ES6 provides a new traversal method for… Of loop, but for… “Of” has a very important aspect

“Can only iterate over objects that implement the Iterator interface.”

So for… “Of” is simply iterator’s hired hand, also known as syntax sugar

Knowing the problems existing in the previous traversal method, the protagonist enters the stage, with the problem, for… How does the OF loop achieve uniform traversal? Keep reading

The Iterator Iterator

Iterator is an interface that provides a unified access mechanism for various data structures. Any data structure can be iterated by deploying the Iterator interface.

1. The function of Iterator

  1. Provide a unified and easy access interface for various data structures

  2. Allows the members of a data structure to be arranged in some order

  3. ES6 created a new traversal command for… The of loop is an Iterator interface for… Of consumption.

2. How Iterator works

  1. Creates a pointer object that points to the start of the current data structure
  2. First callnextMethod that points to the first member of the data structure
  3. Next callnextMethod that moves the pointer back until it points to the last member

Each call to the next method returns a value, which is an Object containing two properties, value and done. Value indicates the returned value, done is Boolean and indicates whether the collection has been traversed, true if it has, and false otherwise.

3. Implement iterator interface by hand

function myIterator(arr) {
    let nextIndex = 0;
    return {
        next: function () {
            return nextIndex < arr.length ? {
                value: arr[nextIndex++],
                done: false}, {value: undefined.done: true}}}}let arr = [1.2.'ljc']
let it = myIterator(arr)
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
Copy the code

MyIterator is an iterator generator that returns an iterator object, which is also a pointer.

We move the pointer through the next method, which internally stores the value of pointer nextIndex through a closure. Each time we call nextIndex, nextIndex will +1, and then fetch data from the array as value according to the value of nextIndex. When no data is available and the maximum index of the array exceeds, no data is returned. In this case, done is true

iterable

Now that we know about Iterator, and we already know how to create an iterator object, this is different from what we said earlier about for… What does the “of” loop matter

First of all we need to know for… Operation mechanism of

When the for… Iterator (); iterator (); iterator (); iterator (); iterator (); iterator (); Of variables, so as to get a specific value, to achieve traversal.

1. Implement iterable objects by hand

A data structure can be considered “traversable” as long as it has the symbol. iterator property.

The symbol. iterator property is itself a function, the default traverser generator for the current data structure, which returns an iterator object.

That is, to implement an iterable, simply deploy the symbol. iterator property on the object and create an iterator method for it

let iteratorObj = {
    items: [1.2.'ljc'].// Deploy the symbol.iterator property
    [Symbol.iterator]: function () {
        let self = this
        let i = 0
        return {
            next: function () {
                // Type is converted to Boolean
                let done = (i >= self.items.length)
                // Data validation
                letvalue = ! done ? self.items[i++] :undefined
                // Data is returned
                return {
                    done,
                    value
                }
            }
        }
    }
}
for (let item of iteratorObj) {
    console.log(item); // 1 2 ljc
}
Copy the code

Obviously implements the Iterator interface, which can be used for… Of Successfully traversal

2. Native application scenarios of Iterator

There are objects for which we do not deploy the Iterator interface, but we can still use for… Of traverses. This is because some objects in ES6 already have this interface deployed by default.

A data structure that has an Iterator interface natively:

  • Array
  • Set the container
  • The map container
  • String
  • The arguments object for the function
  • The NodeList object

Array

Iterator () : iterator (); iterator () : iterator (); iterator () : iterator (); The of loop executes successfully

let arr = [1.2.3]
let it = arr[Symbol.iterator]()// Return an iterator object
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
for (let item of arr) {
    console.log(item);
}
Copy the code

The other several are a routine, not to say

Q&A

Looking at this, you might be wondering why so many data structures are deployed by default, but why not objects?

Of course there’s a reason

Objects may have a variety of properties, unlike arrays where the values are ordered, so we don’t know how to determine the order of the object traversal, so we need to manually implement it, right

Early exit cycle

Normal for loops can be broken at any time, for… The of loop is also available as an upgrade to for and forEach

In addition to the next method, iterators also have two alternative methods: return and throw

The return method is used when for… The return method is called when the of loop exits prematurely.

In particular, the return method must have a return value of type Object

We add the return method to the previous code and add the for… In the of loop, a break statement is used to interrupt the loop, the loop exits prematurely, and the return method is automatically called to output the exit prematurely

let iteratorObj = {
    items: [1.2.'ljc'].// Deploy the symbol.iterator property
    [Symbol.iterator]: function () {
        let self = this
        let i = 0
        return {
            next: function () {
                // Type is converted to Boolean
                let done = (i >= self.items.length)
                // Data validation
                letvalue = ! done ? self.items[i++] :undefined
                // Data is returned
                return {
                    done,
                    value
                }
            },
            return () {
                console.log('Early exit');
                return {
                    done: true
                }
            }
        }
    }
}
for (let item of iteratorObj) {
    console.log(item); / / 1
    break;
}
Copy the code

Pay attention to

If you exit by throwing an exception, the return method is executed before the exception is thrown

Throw methods will be covered in the next generator article

Usage scenarios of the Iterator interface

In addition to the for… In addition to the iterator interface, several scenarios are called automatically by the of loop

1. Deconstruct assignment

When destructuring an iterable, the symbol. iterator method is called by default

let map = new Set().add('a').add('b');
let [x, y] = map
console.log(x, y, map) // a b Set(2)Β {"a", "b"}
Copy the code

Since destructible assignment applies to iterables, let’s try destructing assignment for our own custom iterables

let iteratorObj = {
    items: [1.2.'ljc'].// Deploy the symbol.iterator property
    [Symbol.iterator]: function () {
        let self = this
        let i = 0
        return {
            next: function () {
                // Type is converted to Boolean
                let done = (i >= self.items.length)
                // Data validation
                letvalue = ! done ? self.items[i++] :undefined
                // Data is returned
                return {
                    done,
                    value
                }
            }
        }
    }
}
let [a, b, c] = iteratorObj
console.log(a, b, c)// 1 2 'ljc'
Copy the code

Successful implementation of deconstruction assignment

2. Extend operators

The extension operator also calls the symbol. iterator method by default, which converts the current data structure to an array

// The example of Teacher Ruan
var str = 'hello';
[...str] // ['h','e','l','l','o']
let arr = ['b'.'c'];
['a'. arr,'d']
// ['a', 'b', 'c', 'd']
Copy the code

3. yield*

Yield * is followed by a traversable structure, which invokes the traverser interface of that structure.

let generator = function* () {
  yield 1;
  yield* [2.3.4];
  yield 5;
}
Copy the code

This is not its main battlefield, as explained in the next section

conclusion

New data structures have been added in ES6. In order to provide a unified approach to traversal, for… Of ways. And the for… The iterator is automatically called when the of is executed

Only objects that implement the Iterator interface can use for… of

An iterator is a method that returns an iterator object

Iterator is used in many scenarios in ES6, and it’s worth noting that new things tend to go up

The next article will cover generators

Thank you very much for reading, welcome to put forward your opinion, if you have any questions, please point out, thank you! 🎈