JavsScript 中的 Iterator 迭代器

626 阅读2分钟

背景

JavaScript中存在着Array、Object、String以及ES6引入的Set和Map等可迭代的据结构。这些可迭代的数据结构的迭代方法也是各式各样的。随着ES6迭代器的推出,可以用一个方法来统一数据迭代的江湖了。

ECMAScript 2015的几个补充,并不是新的内置实现或语法,而是协议。这些协议可以被任何遵循某些约定的对象来实现。 有两个协议:可迭代协议和迭代器协议

使用方法

es6中所有可迭代对象的迭代器存放在对象的 Symbol.iterator 属性下。

Set的迭代器使用方法

let mySet = new Set([1,2])
let it = mySet[Symbol.iterator]()
it.next() //{ value: 1, done: false }
it.next() //{ value: 2, done: false }
it.next() //{ value: undefined, done: true }

拥有迭代器的对象都可以使用 for of 进行迭代

let mySet = new Set([1,2])
for(let item of mySet){
    console.log(item)   //1 2
}

定义

迭代器是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历(迭代)操作。
下面是ES6中对迭代器接口的解释:

  • Iterator 接口,包括如下要求:
    Iterator [required]
    • next() {method}: 取得下一个IteratorResult
  • 有些迭代器还扩展支持两个可选成员:
    Iterator [optional]
    • return() {method}: 停止迭代器并返回IteratorResult
    • throw() {method}: 报错并返回IteratorResult
  • IteratorResult 接口指定如下:
    IteratorResult
    • value {property}: 当前迭代值或者最终返回值(如果undefined为可选的)
    • done {property}: 布尔值,指示完成状态

根据迭代器的接口定义,要实现一个迭代器要实现一个next方法,并且next方法返回的结果要满足 : { value: .. , done: true / false }这样的数据结构。(结束done为true)

简单实现

迭代器利用闭包保护保存的特性,实现一个封闭的作用域,并提供一个迭代方法通过修改索引的方式,来读取数据以及状态。

基于迭代器协议,简单实现一个自定义迭代器.

let it = createIterator([1,2])
console.log(it.next())
console.log(it.next())
console.log(it.next())

function createIterator(array){
    let arrayIndex = 0;
    let arrayLength = array.length;
    return {
        next(){
            return {
                value: array[arrayIndex ++],
                done: arrayIndex >= arrayLength
            }
        }
    }
}

基于可迭代协议以及迭代器协议实现可迭代对象


 var Fib = {
    [Symbol.iterator]() {
        var n1 = 1, n2 = 1;
        return {
        // 使迭代器成为iterable [Symbol.iterator]() { return this; },
            next() {
                var current = n2;
                n2 = n1;
                n1 = n1 + current;
                return { value: current, done: false };
            },
            return(v) {
                console.log(
                    "Fibonacci sequence abandoned."
                );
                return { value: v, done: true };
            }
        }; 
    }
};
for (var v of Fib) {
    console.log( v );
    if (v > 50) break;
}

参考资料

  • 你不知道的《javascript》
  • MDN