ES6学习笔记:Iterator接口和Generator函数

一、Iterator接口

Iterator接口为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署了Iterator,就可以完成遍历操作,举个例子:

function customIterator(arr) {
    let nextIndex = 0;
    return {
        next: function() {
            if(nextIndex < arr.length){
                return {value: arr[nextIndex++], done: false};
            }else{
                return {value: undefined, done: true};
            }
        }
    };
}

let it = customIterator(['a', 'b']);
it.next(); //{value: 'a', done: false }
it.next(); //{value: 'b', done: false }
it.next(); //{value: undefined, done: true }

customIterator是实现Iterator接口的遍历器生成函数,调用该函数会返回一个遍历器,其内部有一个指针和一个next方法,每一次调用next方法都会移动指针和返回数据结构当前成员的信息,返回值是一个对象,格式为:{value, done},value是当前成员的值,done是一个布尔值,表示遍历是否结束。

对于Array、Map、Set、String、TypedArray、函数的arguments对象、NodeList对象这些数据结构,Javascript原生给它们部署了Iterator,调用这些数据结构的Symbol.iterator属性即可得到遍历器生成函数:

let arr = ['a', 'b'];
let it = arr[Symbol.iterator]();
it.next(); //{value: 'a', done: false }
it.next(); //{value: 'b', done: false }
it.next(); //{value: undefined, done: true }

二、Generator函数

Generator函数也是一个遍历器生成函数,它的实现方式和Iterator接口完全不同。Generator函数有两个特征,一是function关键字与函数名之间有一个星号,二是函数体内部使用yield表达式,定义不同的内部状态,每一次调用next方法运行到下一个yield并暂停,返回值和Iterator一样,value为yield表达式的值:

function* customGenerator() {
    yield 'a';
    yield 'b';
}

let gt = customGenerator();
gt.next(); //{value: 'a', done: false }
gt.next(); //{value: 'b', done: false }
gt.next(); //{value: undefined, done: true }

换言之,Generator函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。Generator函数调用时不会立即执行,直到调用next方法才开始执行。利用Generator函数这个特性,我们可以写出任意对象遍历器:

function* customGenerator(obj) {
    let propKeys = Reflect.ownKeys(obj);

    for (let propKey of propKeys) {
        yield [propKey, obj[propKey]];
    }
}

let gt = customGenerator({name: 'Jack', age: 30});
gt.next(); //{value: ['name', 'Jack'], done: false }
gt.next(); //{value: ['age', 30], done: false }
gt.next(); //{value: undefined, done: true }

Generator函数也是一个遍历器生成函数,所以将它加到对象的Symbol.iterator属性上面也是可以的:

let person = {
    name: 'Jack',
    age: 30,
    [Symbol.iterator]: function* () {
        let propKeys = Object.keys(this);

        for (let propKey of propKeys) {
            yield [propKey, this[propKey]];
        }
    }
};

let gt = person[Symbol.iterator]();
gt.next(); //{value: ['name', 'Jack'], done: false }
gt.next(); //{value: ['age', 30], done: false }
gt.next(); //{value: undefined, done: true }

三、for...of循环

一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator接口,就可以用for...of循环遍历它的成员:

for(let item of arr){
    console.log(item);
}
//a
//b

for(let item of person){
    console.log(item);
}
//['name', 'Jack']
//['age', 30]


上一篇: ES6学习笔记:Proxy对象
下一篇: ES6学习笔记:Module模块
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags:
最新日志:
评论: 0 | 引用: 0 | 查看次数: 1431
发表评论
登录后再发表评论!