我将
every
实现为生成器以过早地中断迭代:
const every = (f, iter) => function* () {
for (const value of iter) {
const ret = f(value);
yield ret;
if (!ret) break;
}
} ();
const exhaustEvery = iter => {
for (value of iter) {
if (!value)
return false;
}
return true;
};
exhaustEvery(every(x => x % 2 === 1, [1,3,5])); // true
这看起来相当麻烦,因为我必须为每个迭代函数实现单独的排气函数。这是否表明发电机的使用不正确?
every
是一个生成器没有什么意义,因为它本身不生成值,它只是返回 true 或 false,所以它可能只是:
function every(iterator, predicate) {
let value, done;
do {
({ value, done } = iterator.next());
if(!predicate(value)) return false;
} while(!done)
return true;
}
every([1, 2, 3].values(), it => it < 3) // false
如果您知道生成器将结束(生成器不保证),您可以使用
[...res]
分散值。对于您的生成器,您可以只查看最后一个值:
const every = (f, iter) => function*() {
for (const value of iter) {
const ret = f(value);
yield ret;
if (!ret) break;
}
}();
let res = [...every(x => x % 2 === 1, [1, 3, 5])]; // true
console.log(res[res.length - 1])
res = [...every(x => x % 2 === 1, [1, 3, 5, 8, 2, 5, 9])]; // false
console.log(res[res.length - 1])
但是,如果您执行所有这些操作只是为了从生成器生成列表,则可能有更好的方法使用简单的函数。
有无法耗尽的发电机,例如:
function *fibonacci(n) {
const infinite = !n && n !== 0;
let current = 0;
let next = 1;
while (infinite || n--) {
yield current;
[current, next] = [next, current + next];
}
}
// let [...first10] = fibonacci(10);
// alert(first10);
// the above is finite generator and shows how you can exhaust it,
// but what if it is initiated like the following:
let noexhaust = fibonacci();
alert(noexhaust.next().value);
alert(noexhaust.next().value);
alert(noexhaust.next().value);
alert(noexhaust.next().value);
// and so on...
那么,如果你的代码面对一个永无止境的生成器,它应该有什么行为?
从 ECMAScript 2025 开始,我们有了迭代器辅助方法
every
(不要与同名的 Array 方法混淆)。对于您的示例,这将是:
const iter = [1,3,5].values(); // Get an iterator helper object
const result = iter.every(x => x % 2 === 1);
console.log(result); // true