我对 JavaScript 生成器完全陌生。我对 Java 迭代器有很多实际经验,并且用 Java 迭代器链完成了所有软件工作。但我现在才刚刚发现 JavaScript 中的生成器函数和yield,甚至yield*。我想以某种方式添加地图和归约功能。让我们从地图开始吧。
是的,我看过 wu.js,但对我来说,这看起来太像黑客了。一般来说,不反对重新包装,但我有预感,它可以更直接地完成。
这是我所拥有的,首先是范围生成器函数:
function* range(start = 0, end = Infinity, step = 1) {
for(let i = start; Math.sign(step)*(end - i) > 0; i += step)
yield i;
}
[...range(8,0,-1)] // > [8, 7, 6, 5, 4, 3, 2, 1]
太酷了。现在我该如何添加我的地图功能?我发现了这个:
看起来这个 Generator {} 正在邀请我在上面添加一些方法!所以我可以在该范围原型上添加地图:
range.prototype.map = function*(fn) {
for(let x of this)
yield fn(x);
}
[...range(8,0,-1).map(x => 2**x)] // > [256, 128, 64, 32, 16, 8, 4, 2]
哇!但如果我想用一张地图跟随另一张地图,我需要先说这一点:
range.prototype.map.prototype.map = range.prototype.map
[...range(8,0,-1).map(x => 2**x).map(x => x-1)] // > [255, 127, 63, 31, 15, 7, 3, 1]
但我想在所有发电机上粘贴地图。当 IE 恐龙版本 8 上尚不支持数组函数时,我这样做了:
if(!Array.prototype.map)
Array.prototype.map = function(fn) {
var r = [];
for(var i = 0; i < this.length; i++)
r.push(fn(this[i], i, this);
}
这让我可以在 IE 恐龙版 8 中工作,就像在任何像样的浏览器中一样。不需要古怪的 Util.arrayMap(...) 函数。所以我现在很想这样做:
if(!Generator.prototype.map)
Generator.prototype.map = = function*(fn) {
for(let x of this)
yield fn(x);
}
但是呃哦,Generator 不像 Array 那样是全局定义的名称!所以我偷偷溜进去:
range.prototype.__proto__.map = function*(fn) {
for(let x of this) {
yield fn(x);
}
}
[...range(8,0,-1).map(x => 2**x).map(x => x-1)] // > [255, 127, 63, 31, 15, 7, 3, 1]
宾果!我做到了。为了避免使用
__proto__
我也可以这样做:
Object.getPrototypeOf(range.prototype).map = ...
达到同样的效果。
但是除了用这个
range.prototype._proto_
技巧从侧门潜入之外,难道没有更正式的方法吗?
通过更正式的方式,我的意思是直接说一些事情,例如
xxx.Generator.prototype.map = ...
其中 xxx 是定义在其中的任何模块或某些此类 Generator 类?
我想以某种方式添加一个映射和一个归约函数。
从 ECMAScript 2025 开始,这些可作为迭代器辅助方法使用,因此您不再需要创建它们。本机函数返回的迭代器对象是继承这些方法的迭代器辅助对象;对于发电机来说也是如此:
// Your generator
function* range(start=0, end=Infinity, step=1) {
for (let i = start; Math.sign(step) * (end - i) > 0; i += step)
yield i;
}
// Your example adapted to make use of iterator helper methods:
const result = range(8, 0, -1)
.map(x => 2**x)
.map(x => x-1)
.toArray();
console.log(result); // > [255, 127, 63, 31, 15, 7, 3, 1]
请注意,您可以使用扩展语法来获取数组,但我喜欢链接
toArray()
方法(这也是一个迭代器辅助方法)。在我看来,它只是让它看起来更优雅。