ES6精讲09-generator生成器函数

269 阅读3分钟

1.generator生成器函数:

举个🌰例子

function* func() {
    console.log('one');
    yield 2;
    console.log('two');
    yield 3;
    console.log('end');   
}

// 返回一个遍历器对象 可以调用next()
let fn = func();

console.log(fn.next()); //one {value: 2, done: false}
console.log(fn.next()); //two {value: 3, done: false}
console.log(fn.next()); //end {value: undefined, done:true}

🌵小结:

  • 调用generator生成器函数后,生成器不会立即执行,仅仅生成一个迭代器而已,而有了迭代器就可以遍历了,而这个Interator篇讲过

  • generator函数是分段执行的,yield语句是暂停执行next()恢复执行

继续举个🌰例子:

function* gen(x){
  var y = yield x + 2;
  return y;
}

var g = gen(1);
g.next() // { value: 3, done: false }
g.next(2) // { value: 2, done: true }

🌵小结:

  • 第一个 next 方法的 value 属性,返回表达式 x + 2 的值(3)。
  • 第二个 next 方法带有参数2,这个参数可以传入 Generator 函数,作为上个阶段异步任务的返回结果,被函数体内的变量 y 接收。因此,这一步的 value 属性,返回的就是2(变量 y 的值)。

🌵🌵然后是拓展上面的🌰例子(明确y被赋值的时机):

var y;	

function* gen(x){
  	y = yield x + 2;
  return y;
}

var g = gen(1);
g.next(1) // { value: 3, done: false }
console.log(y)//undefined
g.next(11)
console.log(y) // 11
  • 第一次next传参数和不传参数都没用,只是启动了运行,一旦调用 next,函数体就开始执行,一旦遇到 yield 就返回执行结果,暂停执行
  • 第二次 next 的参数会作为第一次 yield 的结果传递给函数体,以此类推,所以第一次 next 调用的参数没用

再举个🌰例子

function* add() {
    console.log('start');
    // x 可真的不是yield '2'的返回值,它是next()调用 恢复当前yield()执行传入的实参
    let x = yield '2';
    console.log('one:'+x);
    let y = yield '3';
    console.log('two:'+y);
    return x+y;  
}
const fn = add();
console.log(fn.next()); //{value:'2',done:false}
console.log(fn.next(20)); //{value:'3',done:false}
console.log(fn.next(30)); //{value:50,done:true}

🌵小结:

  • 第一次调用next,传入的参数是无效的,因为此时生成器内部还没有运行接受参数的一步,即yield操作还没有进行过,第一个值并没有产生,所以是无法接收next的参数的

🌵使用场景:

🤔什么是 for…of 循环?

for...of 语句创建一个循环来迭代可迭代的对象。 在 ES6 中引入的 for...of 循环,以替代 for...inforEach() ,并支持新的迭代协议。for...of 允许你遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构等。

let obj = {
     x:10,
     y:20
}
for(objItem of obj){
      console.log(objItem)
}
// Uncaught TypeError: obj is not iterable
//obj对象是一个不可迭代的对象,或者说它没有迭代器。
// 使用场景1:为不具备Interator接口的对象提供了遍历操作

const obj = {
    name:'小马哥',
    age:18
}

function* objectEntries(obj) {
    // 获取对象的所有的key保存到数组 [name,age]
    const propKeys = Object.keys(obj);
    for(const propkey of propKeys){
        yield [propkey,obj[propkey]]
    }
}

obj[Symbol.iterator] = objectEntries;
// console.log(obj);


// 来看看使用for of来遍历迭代器后会得到什么?
for(let item of objectEntries(obj)){
           console.log(item);  
       }
// ["name", "小马哥"] 
// ["age", 18]

// 这里面相当于直接对item进行了es6解构赋值
       for(let [key,value] of objectEntries(obj)){
           console.log(`${key}:${value}`);  
       }
// name:小马哥
// age:18