function* generatorFn() {
for (const x of [1, 2, 3]) {
try {
yield x;
} catch (e) {
console.log(e); // throw
}
}
}
const g = generatorFn();
console.log(g.next()); //{ value:1, done:false }
g.throw("throw");
console.log(g); // generatorFn {<suspended>}
console.log(g.next()); //{value:3, done:false}
在这个例子中,生成器在try/catch块中的yield关键字处暂停执行 。在暂停期间,throw()方法向生成器对象内部注入了一个错误:字符串‘throw' 。这个错误会被yield关键字抛出 。因为错误是在生成器的try/catch块中抛出的,所以仍然在生成器内部被捕获 。可是,由于yield抛出了那个错误,生成器就不会再产出值2 。此时,生成器函数继续执行,在下一次迭代再次遇到yield关键字时产出了值3 。
四、自定义迭代器
上篇说过对象是没有实现迭代器,也就是说对象没有@@iterator,无法通过Symbol.iterator访问,所以不能遍历对象,为了可以实现对象的遍历,我们需要在对象上实现上面说的迭代器 。通常有两种写法,一种是传统的写法,这种需要自己去控制内部的状态,另外一种是利用生成器函数返回的Generator的迭代器来实现,代码如下:
传统写法
let obj = {
name: "张三",
age: 18,
[Symbol.iterator]: () => {
// 这里不要用this,因为是return fn, this 会丢失
let index = -1,
atrrList = Object.keys(obj);
const objIterator = {
next: () => {
let result = "";
index++;
if (index < atrrList.length) {
result = {
value: atrrList[index],
done: false,
};
} else {
result = {
done: true,
};
}
return result;
},
};
return objIterator;
},
};
for (const iterator of obj) {
console.log("atrrs:" + iterator + ",value:" + obj[iterator]);
}
生成器函数写法
// 为不可迭代的对象添加迭代器
let obj = {
a: 1,
b: 2
}
obj[Symbol.iterator] = function* () {
let keys = Object.keys(obj);
//取到key值的长度
let len = keys.length;
//定义循环变量
let n = 0;
//条件判断
while (n <= len - 1) {
yield { k: keys[n], v: obj[keys[n]] };
n++
}
}
//返回的是个对象的key和value
for (let { k, v } of obj) {
console.log(k, v); // name 张三 age 18
}
总结
生成器是ES6的一个新的函数类型,它并不像普通函数那样总是从运行开始到运行结束 。取而代之的是,生成器yield可以在运行当中暂停,并且等到将来再次next()时再从暂停的地方恢复运行 。
这种交替的暂停和恢复是合作式的双向消息传递,这意味着生成器具有独一无二的能力来暂停自身,这是通过关键字yield实现的 。
【JavaScript迭代器与生成器之生成器】
推荐阅读
- 显示器中的 GSYNC 与 FreeSync 技术原理是什么
- Ajax是什么?JavaScript中如何使用Ajax技术进行网络请求?
- 一篇文章教会你使用JavaScript 创建对象
- 2023年流行的五大JavaScript框架
- 历代的“装饰玉器”:(4)玉镯【三】
- 我的电脑怎么没声音了
- 消失的她:全员演技过关,唯有一人是败笔,演技太烂像AI机器人
- 气鸣乐器包含哪些乐器、单簧气鸣乐器入门介绍
- 台式处理器天梯排行榜2022
- 公式编辑器怎么使用下标
