迭代器
在 JavaScript 中,迭代器是一个对象,它定义一个序列,并在终止时可能返回一个返回值。
说明
迭代器对象含有next方法。利用next()方法返回具有value,done属性的对象。
- value: 序列中的next值
- done: 表示序列是否结束,如果是最后一个值为true
特点
- 如果
value和done一起存在,则它是迭代器的返回值。 - 一旦迭代器产生终止值之后,再对调用next()应该继续返回{done:true}
- 一旦创建,迭代器对象就可以通过重复调用 next()显式地迭代
示例: 自定义迭代器
自定义迭代器需满足的条件
- 迭代器对象必须有 next方法
- next方法中必须返回具有
value,done属性的对象- 当迭代器产生终值的时候,在调用next方法还需返回 含有
done为true的对象
function makeRangeIterator(start = 0, end = Infinity, step = 1) {
let nextIndex = start;
let iterationCount = 0;
const rangeIterator = {
next: function() { // 定义next方法
let result;
if (nextIndex < end) {
result = { value: nextIndex, done: false }
nextIndex += step;
iterationCount++;
return result; // done为false,可继续迭代
}
return { value: iterationCount, done: true } // 返回执行次数和done, 终止迭代
}
};
return rangeIterator; // 返回迭代器对象
}
// 使用
let it = makeRangeIterator(1, 10, 2);
let result = it.next();
while (!result.done) {
console.log(result.value); // 1 3 5 7 9
result = it.next();
}
console.log("Iterated over sequence of size: ", result.value); // 5
生成器
可以定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态(比迭代器很简洁好用)
说明
生成器最初调用时,生成器不执行任何代码,而是返回一个Generator的迭代器。 通过调用生成器的next()方法消耗值时,Generator 函数将执行,直到遇到 yield 关键字
特点
- 使用
function*语法编写,结合yield关键字 - 生成器函数在执行时能暂停,后面又能从暂停处继续执行
yield后面紧跟迭代器要返回的值,yield*则表示将执行权移交给另外一个生成器对象(yield后面需要紧跟可迭代对象时使用) 示例: 使用function*+yield定义生成器
function* idMaker(){
var index = 0;
while(index<3)
yield index++;
}
var gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
console.log(gen.next().value); // undefined
function* 定义生成器函数,yield后面紧跟需要迭代器返回的值
属性方法介绍
.next(value)
调用next方法时传值
- 传递给 next() 的参数值会被 yield 接收。要注意的是,传给第一个 next() 的值会被忽略
- 调用next()方法时,如果传入了参数,那么这个参数会传给上一条执行的 yield 语句左边的变量(也就是下修改上一次yeild的值)
示例:
function *gen(){
yield 10;
x=yield 'foo';
yield x;
}
var gen_obj=gen();
console.log(gen_obj.next());// 执行 yield 10,返回 10
console.log(gen_obj.next());// 执行 yield 'foo',返回 'foo'
console.log(gen_obj.next(100));// 将 100 赋给上一条 yield 'foo' 的左值,即执行 x=100,返回 100
console.log(gen_obj.next());// 执行完毕,value 为 undefined,done 为 true
.return(value)
(返回具有value,done属性的对象)
- 已经处于完成状态的生成器调用
return(value),生成器将保持在完成状态 - 调用
return()时提供参数,则value的值就是最后的返回值,否则和调用next()相同效果
const createReturnVal = ()=>{
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
console.log(g.next()); // { value: 1, done: false }
console.log(g.next()); // { value: 2, done: false }
console.log(g.next()); // { value: 3, done: false }
console.log(g.next()); // { value: undefined, done: true }
console.log(g.return()); // { value: undefined, done: true }
console.log(g.return(1)); // { value: 1, done: true }
console.log(g.next()); // { value: undefined, done: true }
}
createReturnVal()
throw()
(返回具有value,done属性的对象)
强制生成器抛出异常,并传递应该抛出的异常值。
这个异常将从当前挂起的生成器的上下文中抛出,就好像当前挂起的 yield 是一个 throw value 语句。
说明
- 抛出的异常可以被
try...catch块捕获 示例
function* gen() {
while(true) {
try {
yield 42;
} catch(e) {
console.log("Error caught!");
// console.log(e); // "error"
}
}
}
var g = gen();
console.log(g.next()); // { value: 42, done: false }
console.log(g.throw(new Error("Something went wrong")));
// "Error caught!"
// {value: 42, done: false}
console.log(g.throw('error')); // "error"
yiled*
用于委托给另一个generator或可迭代对象 一般用于yeild 需要返回可迭代对象时使用(需要二次迭代时使用,可任意直接迭代类数组的可迭代对象,不含object) 基础示例1
function* g3() {
yield* [1, 2];
yield* "34";
yield* arguments;
// yield* {a:1,length:1}; // 报错:Uncaught TypeError: object is not iterable
}
var iterator = g3(5, 6);
console.log(iterator.next()); // { value: 1, done: false } // 迭代[1,2]
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: "3", done: false } // 迭代 "34"
console.log(iterator.next()); // { value: "4", done: false }
console.log(iterator.next()); // { value: 5, done: false }
console.log(iterator.next()); // { value: 6, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
基础示例2
function* g4() {
yield* [1, 2];
return "foo";
}
var result;
function* g5() {
result = yield* g4();
}
var iterator = g5();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: undefined, done: true },
// 此时 g4() 返回了 { value: "foo", done: true }
console.log(result); // "foo"
生成器和迭代器的区别
- 自定义的迭代器需要明确的返回包含value和done的对象
- 自定义生成器比迭代器简介,可以通过yield返回符合规范的包含value和done的对象
生成器和迭代器的使用场景
- 当需要对一个对象进行迭代时(比如开始用于一个
for..of循环中) - 遍历/迭代/扩展运算符时
参考 developer.mozilla.org/zh-CN/docs/… developer.mozilla.org/zh-CN/docs/…