Bootstrap

一文大白话讲清楚ES6迭代器Iterator和生成器Generator的原理和作用

一文大白话讲清楚ES6迭代器Iterator和生成器Generator的原理和作用

1. 是啥迭代器Iterator

  • 迭代迭代,就是一个接着一个,怎么一个接着一个呢,就是next(),在next()
  • 迭代器是一种特殊的对象,每个迭代器都有一个next()方法,每次调用next方法都会返回一个结果对象,结果对象有两个属性,一个是value,一个是done。value表示本次next()所取到的值,而done是布尔值,表示是不是已经取完所有值
  • 迭代器内部有一个指向集合中值的位置额指针,每次next()以后,该指正移动到下一个值得位置
  • 所以我们很容易设计一个迭代器
  • 上代码
function createIterator(items){
    let i=0;
    return {
        next:function (){
            let done=(i>=items.length)
            let value=!done?items[i++]:undefined;
            return{
                done,
                value
            }
        }
    }
}
let iterator=createIterator([1,2,3,4,5])
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
// { done: false, value: 1 }
// { done: false, value: 2 }
// { done: false, value: 3 }
// { done: false, value: 4 }
// { done: false, value: 5 }
// { done: true, value: undefined }

2. 啥是生成器Generator

2.1 生成器的理解

  • 上面讲了迭代器,生成器是啥,生成器就是生成迭代器的方法
  • 说白了,就是用生成器生成迭代器
  • 怎么生成了,两个关键*标明方法名为迭代器,然后用yield语句进行迭代
  • 上代码
function *generator(items){
    for (var i = 0; i < items.length; i++) {
        yield items[i]
    }
}
let iterator=generator([1,2,3,4,5])
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
// { done: false, value: 1 }
// { done: false, value: 2 }
// { done: false, value: 3 }
// { done: false, value: 4 }
// { done: false, value: 5 }
// { done: true, value: undefined }
  • 当然,generator本身是个普通函数,他可以有返回值
function *generator(items){
    let num=0;
    for (var i = 0; i < items.length; i++) {
        num++
        yield items[i]
        
    }
    if(num>=items.length){
        return 'over'
    }
    
}
let iterator=generator([1,2,3,4,5])
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: 4, done: false }
// { value: 5, done: false }
// { value: 'over', done: true }

  • 发现没有,如果有返回值,最后一项的value是返回值,而不是undefined的了
  • 所以,generator的整体运行逻辑是这样的
  1. 被调用生成迭代器本身
  2. 调用next()方法开始执行
  3. 执行遇到yeild,就暂停后面的操作,并把紧跟在yield后面的表达式的值作为返回对象的value属性值,done值为true
  4. 再次调用next()方法,再继续往下执行,直到遇到新的yield,
  5. 重复执行,直到碰到return或者执行完;如果碰到return,则罢return的值作为返回对象value的属性值,done为false。如果没有碰到return,就把undefined作为返回对象value的属性值,done为false。表示迭代完成

2.2 next传参

  • next既然是一个方法,那我们就可以向next()方法传入参数,传入的参数会被当成上一个yield的返回值‘
function *calculate(num){
    let x=3*(yield(num+2))
    let y=yield (x/4)
    return (num+x+y)
}
let iterator=calculate(10)
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// console.log(iterator.next())
// { value: 12, done: false }
// { value: NaN, done: false }
// { value: NaN, done: true }
// { value: undefined, done: true }
console.log(iterator.next())
console.log(iterator.next(16))
console.log(iterator.next(3))
// { value: 12, done: false }
// { value: 12, done: false }
// { value: 61, done: true }

  • 分析一下,都怎么打印出来的
  1. 调用calculate(10)生成迭代器,这时候迭代器里面的num=10
  2. 执行next,碰到yield(num+2),停下来,返回num+2,也就是12//12
  3. 执行next(12),传入的参数相当于上一次yield的返回值,也就是说,此时yield(num+2)=16,所以x=3816=48;执行到yield (x/4)时,听,返回x/4=12//12
  4. 执行next(3),同理,相当于yield (x/4)=3,也就是y=3,执行到return,结束,返回num+x+y=10+48+3=61//61
  5. 结束

2.3 for…of遍历

  • 因为generator返回Iterator对象,所以我们可以使用for…of进行遍历
function *generator(items){
    for (var i = 0; i < items.length; i++) {
        yield items[i]
    }
}
let iterator=generator([1,2,3,4,5])
for (var x of iterator) {
    console.log(x)
}
// 1
// 2
// 3
// 4
// 5

  • 我们也可以对原生对象加上generator,是的他可以通过for…of进行遍历
function *objGenerator(obj){
    let propKeys=Reflect.ownKeys(obj)//Reflect.ownKeys返回一个数组,包含对象自身的所有属性,包含Symbol,也包含不可枚举
    for (var x of propKeys) {
        yield[x,obj[x]]
    }
    
}
let obj={
    name:'tom',
    age:12,
    hight:153
}

let objIterator=objGenerator(obj)
for (var [key,value] of objIterator) {
    console.log(key,value)
}
// name tom
// age 12
// hight 153

3.generator异步处理

function *generator () {
 const f1 = yield readFile('variable.js');//异步任务
 const f2 = yield readFile('index.html');//异步任务
};
let g=generator()
g.next()
g.next()//等待上一个异步任务执行完毕,再执行下一个异步任务

4. generator的语法糖,更便捷的async和await

  • async和await其实就是generator的语法糖,更为简洁,语义化更强
async function generator () {
 const f1 = await readFile('variable.js');//异步任务
 const f2 = await readFile('index.html');//异步任务
};
let g=generator()

;