迭代器和生成器

155 阅读2分钟

迭代器

可迭代协议

一个对象要想成为可迭代对象,必须实现@@iterator 方法。这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,可通过常量 Symbol.iterator访问该属性。

迭代协议

代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式。当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值。只实现了拥有以下协议的next方法,一个对象才能成为迭代器。

手动实现一个迭代器

function createrIterator(array){
    var pointer=0;
    return {next: function(){
        let done=pointer>=array.length;
        let value=!done?array[pointer++]:'undefined';
        return {done,value}
      }
    }
}

对象没有迭代器

对象是没有迭代器的,所以不能使用for...of循环,对象要想使用for...of循环必须定义[Symbol.Iterator]属性。建立[Symbol.Iterator]属性有两种方式

  • 第一种类似上面的手动实现迭代器
let obj={name:'a',color:'b'};
obj[Symbol.iterator]=function(){
    let keys=Object.keys(obj);
    let pointer=0;
    return {
        next:function(){
            let done=pointer>=keys.length;
            let value=!done?{keys[pinter]:obj[keys[pointer]]}:'undefined';
            return {done,value}
        }
    }
}

  • 第二钟运用generator
let obj={name:'a',color:'b'};
obj[Symbol.iterator]=function *(){
    let keys=Object.keys(obj);
    for (let propsKey of keys){
        yield {
            key:propsKey,
            val: obj[propKey]
        }
    }
}

** 迭代器总结**

一个对象要想成为一个可迭代对象,必须要有[Symbol.Iterator]迭代器,迭代器必须拥有next方法,next方法返回done和value。

generator

生成器对象是由一个 generator function 返回的, 既是一个迭代器,也是一个可迭代对象。generator跟函数很像,定义如下:

function* foo(x) {
    console.log('调用第一次next方法才执行')
    yield x + 1;
    yield x + 2;
    return x + 3;
}
let result=foo(0);
result.next()//{done:false,value:1}
result.next()//{value: 2, done: false}
reult.next()//{value,done:true}
  • 在上面调用foo()只是生成一个generator对象,不会执行里面的代码。所以console.log()
  • 第一次调用next()会打印console,并且返回{done:false,value:1}
  • 第三次调用next(),因为使用了return ,返回{value:3.done:true},在generator中使用return表示结束生成器

异步迭代器Symbol.asyncIterator

在ES9中引入了异步迭代器,可用于for await...of循环。它与上面迭代器的主要区别就是调用next方法返回的是promise而不是对象

给对象添加异步迭代器

/*** 常规写法****/
let obj={name:'a',color:'b'};
obj[Symbol.asyncIterator]=function(){
    let keys=Object.keys(obj);
    let pointer=0;
    return {
        next:function(){
            let done=pointer>=keys.length;
            let value=!done?{keys[pinter]:obj[keys[pointer]]}:'undefined';
            return  Promise.resolve({done,value})
        }
    }
}

/*** 用异步生成器****/

obj[Symbol.asyncIterator]=async function* createIterator(obj){
    let keys=Object.keys(obj);
    for (let propsKey of keys){
        yield {
            key:propsKey,
            val: obj[propKey]
        }
    }
}

** 用for await of执行异步生成器**

(async ()=>{
   for await (let x of obj){
       console.log(x);
   } 
)()

参考

developer.mozilla.org/zh-CN/docs/…

developer.mozilla.org/zh-CN/docs/…

developer.mozilla.org/zh-CN/docs/…