使用JavaScript生成器函数生成范围
生成器函数
JavaScript ES6生成器允许您定义可以退出并稍后重新进入的函数,同时保留其上下文(变量绑定)。它们使用function*
(function
关键字后跟一个星号)进行定义,并使用yield
表达式返回其结果。例如:
function* generateRange(end, start = 0, step = 1) {
let x = start - step;
while(x < end - step) yield x += step;
}
const gen5 = generateRange(5);
let x = gen5.next();
while (!x.done) {
console.log(x.value);
x = gen5.next();
} // 输出:0, 1, 2, 3, 4
在上面的示例中,我们定义了一个生成器函数generateRange
,它将返回start
和end
之间的每个值,每次增加step
。我们使用生成器对象调用Generator.prototype.next()
,直到它返回{value: undefined, done: true}
,以迭代生成器产生的值。
Symbol.iterator
Symbol.iterator
指定了对象的默认迭代器。通常情况下,Symbol.iterator
使用生成器函数来实现。例如:
const iterableXx = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
}
};
```js
console.log([...iterableX]); // [1, 2]
如你在这个例子中所看到的,通过将一个生成器函数赋值给对象的Symbol.iterator
属性,可以使对象成为可迭代的。这在你想要迭代一些任意的数据或者创建一个可迭代的对象并在内部使用生成器函数时非常方便。
将所有内容整合在一起
了解了这两个概念的工作原理后,我们可以将它们结合起来创建一个类似于Python或Ruby的范围生成器:
const range = (end, start = 0, step = 1) => {
function* generateRange() {
let x = start - step;
while(x < end - step) yield x += step;
}
return {
[Symbol.iterator]: generateRange
};
}
console.log([...range(7)]); // [0, 1, 2, 3, 4, 5, 6]
for (let i of range(8, 2, 2)) console.log(i); // Logs: 2, 4, 6