今天看了一下这块的东西,文档不是很好理解。但是完完整整看下来,文档还是很全的。
这里算是总结一下在看生涩的文档之前可以了解的东西,方便看文档的时候好理解。
1,什么是生成器函数(function*)
生成器函数简单理解就是这个函数返回一个可枚举的对象(官方说法返回Generator??对象)。可以通过.next()枚举其中的数据。内部通过yield关键字实现步进。
2,为什么要有一个生成器函数(function*)这种特殊的语法,
C#也有yield,但是并没有特殊的语法。下面链接是es委员会一员的回答。https://stackoverflow.com/questions/27778105/whats-the-purpose-of-an-asterisk-in-es6-generator-functions/27787527
说实话,第二条没在看懂。就感觉是弱类型语言的毛病。
3,看迭代器和生成器这部分是看到,“传给第一个?next()?的值会被忽略”,为什么。
其实生成器函数文档中已经有说明,“调用?next() 方法时,如果传入了参数,那么这个参数会传给上一条执行的 yield语句左边的变量”。下面我们通过一段代码理解一下。
function* countAppleSales () {
console.log("生成器函数第一行代码");
var saleList = [0,1,2,3,4,5];
for (var i = 0; i < saleList.length; i++) {
var re = yield saleList[i];
console.log(`re:${re}`)
if(re===true){
i=4;
}
}
}
var appleStore = countAppleSales(); // 调用生成器函数不执行任何代码,而是返回迭代器。
console.log("开始调用");
console.log(appleStore.next(false)); //第一次next(),从生成器函数第一行代码开始执行,执行到第一次遇到 yield,返回 { value: 0, done: false }.
//此时传入的参数(false)没机会给“yield左边的变量”re赋值.
console.log("------------------");//分割线
console.log(appleStore.next(true)); //第二次next(),从上一次yield截断处继续执行,直到再次遇到yield。
//执行代码如下
//1,先给“yield左边的变量”re赋值,值为next()的参数,这里为true。执行打印“re:true”。后面i赋值为4,下一次循环i++,此时i为5。再次走到yield 返回{ value: 5, done: false }。
下面是最终的执行结果
开始调用
生成器函数第一行代码
{ value: 0, done: false }
------------------
re:true
{ value: 5, done: false }
看完这些再看文档,特别是翻译的中文文档应该会好点,希望对你有所帮助。
下面说一个使用场景,也是看到这里才学生成器函数的。
https://es6.ruanyifeng.com/#docs/array#%E6%89%A9%E5%B1%95%E8%BF%90%E7%AE%97%E7%AC%A6%E7%9A%84%E5%BA%94%E7%94%A8? 直接看第五部分。
Number.prototype[Symbol.iterator] = function*() {
let i = 0;
let num = this.valueOf();
while (i < num) {
yield i++;
}
}
console.log([...5]) // [0, 1, 2, 3, 4]
上面代码中,先定义了Number对象的遍历器接口,扩展运算符将5自动转成Number实例以后,就会调用这个接口,就会返回自定义的结果。
给自定义对象加枚举器
let arrayLike = {
arr:[0,1,2,3]
};
arrayLike[Symbol.iterator] = function*() {
let num = this.valueOf();
// num.arr.forEach(element => {
// yield element;//报错。forEach里面是传了一个函数进去,所以yield语句实际上在一个不是生成器的函数里面,所以报错。
// });
for(let item of num.arr){
yield item;
}
}
console.log([...arrayLike]);
|