Skip to main content

生成器 + 迭代器

迭代器可以用生成器语法,也可以不用

但是生成器本身是对低级迭代器的高级包装(自动实现了迭代器的 next 方法),虽然可以用于更高级的迭代器

使用主要是为了允许你定义一个不会被连续执行的函数作为迭代算法

在 JavaScript 中,迭代器是一个对象,它定义一个序列,并在终止时可能附带一个返回值。

更具体地说,迭代器是通过使用 next() 方法实现了迭代器协议的任何一个对象,该方法返回具有两个属性的对象:

value 迭代序列的下一个值。

done 如果已经迭代到序列中的最后一个值,则它为 true。如果 value 和 done 一起出现,则它就是迭代器的返回值。

一些语句和表达式专用于可迭代对象,例如 for...of 循环、展开语法、yield* 和解构语法。

function* fibonacci() {
let current = 0;
let next = 1;
while (true) {
const reset = yield current;
[current, next] = [next, next + current];
if (reset) {
current = 0;
next = 1;
}
}
}

const sequence = fibonacci();
console.log(sequence.next().value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
console.log(sequence.next().value); // 3
console.log(sequence.next().value); // 5
// 手动传入 reset 为 undefined
console.log(sequence.next().value); // 8
// 手动传入 reset 为 true
console.log(sequence.next(true).value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2

迭代器

function makeRangeIterator(start = 0, end = Infinity, step = 1) {
let nextIndex = start;
let iterationCount = 0;

const rangeIterator = {
next() {
let result;
if (nextIndex < end) {
result = { value: nextIndex, done: false };
// 一次进一个 step
nextIndex += step;
iterationCount++;
return result;
}
return { value: iterationCount, done: true };
},
};
// 返回迭代器对象
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(`已迭代序列的大小:${result.value}`); // 5
function* makeIterator() {
yield 1;
yield 2;
}

const it = makeIterator();

for (const itItem of it) {
console.log(itItem);
}

console.log(it[Symbol.iterator]() === it); // true

// 这个例子向我们展示了生成器(迭代器)是可迭代对象,
// 它有一个 @@iterator 方法返回 it(它自己),
// 因此,it 对象只能迭代*一次*。

// 如果我们将它的 @@iterator 方法改为一个返回新的迭代器/生成器对象的函数/生成器,
// 它(it)就可以迭代多次了。

it[Symbol.iterator] = function* () {
yield 2;
yield 1;
};