The meaning and usage of iterators

  • Scotland team
  • Author: aishery

What is an iterator

Iterator is a mechanism used to achieve uniform traversal operation for different collections, API as long as the deployment of the Iterator interface to traverse the data structure needed by calling this interface, consumption or use of this interface traversal operation.

Iterator pattern

Before touching the iterator, with first understand what is an iterative mode, recall stories of our lives. We need to buy tickets in time to visit the scenic area, the conductor needs to be done, everyone he will line up for tickets ticket in turn, ordinary adults, students, children are sequentially ticket. Conductor need to follow certain rules, certain order to visit the staff does not fall sold a ticket, in fact, this process is ergodic, corresponding computer design pattern is an iterative mode. Iterative mode, there is provided a method of sequential access to various elements of a polymeric object, without exposing the interior of the object representation.

Why should iterator

Recall that in our javascript, there are many ways to traverse the structure as well. JavaScript original means "a collection of" data structures, mainly Array (Array) and the object (Object), ES6 has added a Map and Set, so there are four data sets, while traversing four has a different structure Methods. For chestnut, the server providing data for data visualization of a distal tip, the data traversed display used for, but because of the business changes, so that the data structure returned by the backend change, return the object or set, map, traversing the amount of code rewrite lead distal end. The aim is to standardize the iterator iteration.

How to deploy iterator interface

ES6 introduced a standardized interface for the implicit iterator. Javascript many built-in data structures, such as the arguments object Array, Map, Set, String, TypedArray, function, NodeList object has Iterator interface. Can print in a console Array instance, the prototype has a view on Symbol.iterator property (Symbol.iterator fact Symbol ( 'Symbol.iterator') shorthand property name is Symbol type represent this property unique and can not be rewrite coverage), it is the iterator function to perform this function, it will return an iterator object.

Although Javascript many built-in data structures already implements the interface, and some structures are not the iterator interface (such as object), how to do that, we need to write an iterator, then we need to know how iterators work. The following code implements a simple iterator:

   //迭代器就是一个函数,也叫迭代器生成函数
function Iterator(o){
    let curIndex = 0;
    let next = () => {
        return {
            value: o[curIndex],
            done: o.length == ++curIndex
        }
    }
    //返回迭代对象,该对象有next方法
    return {
        next
    }
}
let arr = [1,2]
let oIt = Iterator(arr)
oIt.next();//{value:1,done:false}
oIt.next();//{value:2,done:false}
oIt.next();// {value: undefined, done: true}
oIt.next();// {value: undefined, done: true}
复制代码

Call the iterator function returns an object that is the iterator object, with the next method on the object, each call to the next method, will return information about the current members of the data structure. Specifically, it is return an object value and done two properties. Which, value property is the value of the current member, done attribute is a Boolean value that indicates whether the end of the traverse.

next () iterator

In the call to the next method above chestnuts, note that:

  • At the time of obtaining the last element of the array, iterator does not report done: true, this time need to call again next (), over the value of the end of the array, complete signal to get done: true.
  • Typically, in iterations have been completed iterator object will continue to call the next method continues back {value: undefined, done: true} without error.

Optional return () and throw ()

In addition to traversing the object must have a next method, it may also have an optional method and the return throw method.

return method is defined as a signal is transmitted to the iterator value that it will not remove any mention among consumers.

        Object.prototype[Symbol.iterator] = function () {
            let curIndex = 0;
            let next = () => {
                return {
                    value: this[curIndex],
                    done: this.length == curIndex++
                }
            }
            return {
                next,
                return() {
                    console.log('执行return啦')
                    return {}
                }
            }
        }
        let obj = {
            0: 'a',
            1: 'b',
            2: 'c'
        }
        //自动调用---遇到对迭代器消耗提前终止的条件
        for (let item of obj) {
            if (item == 'c') {
                break
            } else {
                console.log(item)
            }
        }
       //自动调用---抛出异常
        for (let item of obj) {
            if (item == 'c') {
                throw new Error('Errow')
            } else {
                console.log(item)
            }
        }
        //手动调用
        let ot = obj[Symbol.iterator]()
        console.log(ot.return())
复制代码

In the above code, the method can throw performed automatically invoked in certain circumstances, may be manually invoked. The main methods throw an exception report to the iterator / error, generally used with the generator.

Iterator categories

Iterator iterator divided into internal and external iterators.

  • Internal iterators: itself is a function that defined the internal rules of iterations, fully accepted throughout the iterative process, requiring only one call. For example Array.prototype.forEach method, jQuery.each iterators are internal.
  • External iterator: is itself a function, execution returns iterator object is a next iteration element must explicitly call. Use forEach traverse, all of the data can only disposable pull consumption, may be used iteratively in a manner to control the behavior of one step, so that the iterative process is more flexible and controllable.

Use iterator

After implement iterator interface, how to use?

let arr = ['a', 'b'];
let iter = arr[Symbol.iterator]();

iter.next() // { value: 'a', done: false }
iter.next() // { value: 'b', done: false }
iter.next() // { value: undefined, done: true }
复制代码

In addition to the above code such as individual users, to achieve the purpose of this interface, all data structures is to provide a single access mechanism. Implements this interface, you can call ES6 in the new API by calling Iterator interface, such as for..of is a typical consumption iterator API. The following specific look at the implementation of the principle of for..of:

let arr = [1,2,3];
for(let num of arr){
  console.log(num);
}
输出结果为:1,2,3
复制代码

for-of loop function first calls of arr Symbol.iterator properties of an object array, the array will be obtained corresponding iterator, followed Iterator.next () is called, value attribute iterator result of the object will be placed to the variable num. Data items are sequentially stored in the array to the variable num until the result iterator object done until the property becomes true, the cycle ends. for-of the cycle to completely remove the need for loop track collection index, better set of operations focused on content.

ES6 specified, the default Iterator interface deployed in Symbol.iterator attribute data structure, or that a data structure as long as Symbol.iterator properties, can be considered to be "traversed" (iterable). You can use the above default will call Iterator function API, and if the data structure does not provide an implementation of this interface (for example, the object), how should like to maximize interoperability it? Then you can build your own to meet this standard iterators. The following is an example of adding the Iterator interface object:

        let obj = {
            0: 'a',
            1: 'b',
            2: 'c',
            length: 3,
            [Symbol.iterator]: function () {
                let curIndex = 0;
                let next = () => {
                    return {
                        value: this[curIndex],
                        done: this.length == curIndex++
                    }
                }
                return {
                    next
                }
            }
        }
        for (let item of obj) {
            console.log(item)
        }
复制代码

If [Symbol.iterator] attribute to delete the object, then it will error Uncaught TypeError: obj is not iterable, tell us obj is not traversed.

In addition to the cycle shown above can be a for..of a consumption iterator, there are other structures may be used to consume ES6 iterator. For example spread operator:

        function f(x, y, z) {
            console.log(x, y, z)
        }
        f(...[2, 3, 1])
复制代码

And the structure assignment may be partially or completely consumed an iterator:

        let arr = [1, 2, 3, 4, 5]
        var it = arr[Symbol.iterator]()
        //部分消耗
        var [x, y] = it
        console.log(x, y) //打印1 2
        //完全消耗
        var [y, ...z] = it
        console.log(y, z) //打印3 [4,5]
复制代码

JavaScript generated by default iterator API

Produce iterator objects, we can produce iterator objects by defining an iterator function, JavaScript can also call the iterator functions defined in the built-in data structure to produce. In addition, for the array and ES6 added several new data structures MAP, Set, these collections have been deployed not only in itself iterator interface, API also provides a method to generate an iterator object. ES6 array, Set, Map deploy the following three methods return visitor object after the call.

  • entries () returns an object traversing for traversing the [key name, key] array thereof.
  • keys () Returns a visitor object, through all of the keys used.
  • values ​​() Returns a visitor object, through all of the keys used.

Example array iterator

Here is the iterator interface using an array:

let arr = [1,2,3,4]
let arrEntires = arr.entries()
arrEntires.next() //{value: [0, 1], done: false}
let arrKeys = arr.keys() //对于数组,索引值就是键值
arrKeys.next() //{value: 0, done: false}
let arrValues = arr.values()
arrValues.next() //{value: 1, done: false}
复制代码

As can be seen in the following code for the traversal of the array ... iterator interface is the default values

for(let item of [1,2,3]) {
 console.log(item)// [1,2,3]
}
复制代码

Set an example using iterators

Here is the iterator interface using the Set:

let set = new Set([1,2,3,4])
let setEntires = set.entries()//对于 Set,键名与键值相同。
 setEntires.next() //{value: [1, 1], done: false}
let setKeys = set.keys()
 setKeys.next() //{value: 1, done: false}
let setValues = set.values()
setValues.next() //{value: 1, done: false}
复制代码

As can be seen Set default iterator interface [Symblo.iterator] values ​​are

for(let item of new Set([1,2,3,4])){
 console.log(item)// [1,2,3,4]
}
复制代码

Map iterator use case

Here is the Map iterator interface:

let map = new Map([[1,2],[3,4]])
let mapEntires = map.entries()

mapEntires.next() //{value: [1, 2], done: false}
let mapKeys = map.keys() 
mapKeys.next() //{value: 1, done: false}
let mapValues = map.values()
mapValues.next() //{value: 2, done: false}
复制代码

Map default iterator interface [Symblo.iterator] entries you are;

for(let item of new Map([[1,2],[3,4]])){
 console.log(item)// [1,2] [3,4]
 }

复制代码

Why objects are not built iterator interface

In the above, we refer to the object can not set the default method of iteration, iteration is not the object, its performance is not [Symbol.iterator] property. Although the target for us, is a way of key-value store, although not so good map, key can only be strings, but sometimes the object is to be iterative, but why not give the object can set the default iteration method?

The reason is because, for the object of the traversal, the traversal needs to consider the properties of the object itself or on the object itself may traverse an enumeration traversal attribute or attributes on the prototype or enumeration traversal attribute or may even [Symbol.iterator] on prototype We hope to traverse it. Given the conflicting views and way meet existing traverse, so there is no set standard will [Symbol.iterator] to join.

A method of generating iterator object

Above, we tried to add a Symbol.iterator method for an object, the object of which is to generate traversal function, call the function returns a visitor object of the object.

In addition to the above direct way to generate iterator object in this add Visitor object generation function according to the iterator protocol, what way can generate an iterator object? Yes, it is a special function, called generator.

var it = {};
it[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};
//可以被...遍历,说明已经部署成功
console.log([...it])// [1, 2, 3]
let myIterator = it[Symbol.iterator]()
console.log(myIterator.next())//{value: 1, done: false}
console.log(myIterator.next())//{value: 2, done: false}
console.log(myIterator.next())//{ value: 3, done: false }
console.log(myIterator.next())//{ value: undefined, done: true }
复制代码

In the above code, the generator does not function much code, only to return values ​​using each keyword yeild next () a.

Builder is a special form of the function, generator function declaration syntax is:

function *bar(){
    // ...
}
复制代码

* Before and after can be a space without a space. Although the statement generator function and normal function are different, but the execution and normal function, and they can pass parameters. What The main difference is it?

Function is a code block period to perform specific tasks, the function performed, which is equivalent to a code block is executed. Function begins execution, it will not be interrupted prior to completion of execution, all of the code block is executed. Before the introduction of the ES6 function generator Yes it is executed, but described earlier to an external iterator iterators can be compared to the internal control of the iterative process, when consumed, iterator object again next click. Similarly iterative process, the process control can be performed as a function, the function does not need to be performed once completed.

Performing a generator function returns an iterator object to control the generator function executes its code. Therefore, the execution of the function becomes controllable. You can also use the new keyword yield in the Builder, used to mark a pause point. Iterator addition to the control function performed, but also be two-way transmission of information during each pause, the pause mode generator function returns a value, the recovery time iterator execution may pass a value to the intrinsic function by parameter passing to the next method . It can be understood as a reference multiple passages, a plurality of return value.

Since This part describes the iterator more about generator Benpian do too much introduction, introduction to iterator, please add and correct me.

Reproduced in: https: //juejin.im/post/5d0c2f3ef265da1b8b2b6584

Guess you like

Origin blog.csdn.net/weixin_33951761/article/details/93176761