如何使用返回生成器对象并能够链接它们的函数扩展Array?
我尝试扩展Array,以查看是否可以链接生成器函数。第一次调用有效,但下一个调用无效,因为它返回一个生成器对象,我不知道如何扩展它。
Array.prototype.select = function* (fn) {
let it = this[Symbol.iterator]();
for (let item of it) yield fn(item);
}
Array.prototype.where = function* (fn) {
let it = this[Symbol.iterator]();
for (let item of it) {
if (fn(item)) yield item;
}
}
我希望能够将这样的生成器链接到一个数组
let result = arr.select(v => v * 2)
.where(v => v % 3 === 0);
for (let item of result) console.log(item);
答案 0 :(得分:2)
您可以将这两种方法都存储为Object
的原型函数,并移交迭代器对象,因为这两个函数都使用生成器并返回可迭代的对象。
Object.prototype.select = function* (fn) {
for (let v of this) yield fn(v);
}
Object.prototype.where = function* (fn) {
for (let v of this[Symbol.iterator]()) if (fn(v)) yield v;
}
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9],
result = array[Symbol.iterator]()
.select(v => v * 2)
.where(v => v % 3 === 0);
console.log(...result);
答案 1 :(得分:1)
在不修改Object
的情况下,您仍然可以使用我创造的技术"superclassing"使这些方法可链接。
首先定义要Array
扩展的基类,然后修改Array
的原型链以人为地扩展基类。
请注意select()
和where()
方法如何封装原始的生成器函数以返回该类的新实例,以便这些方法可链接。
class Enumerable {
constructor (getIterator) {
this[Symbol.iterator] = getIterator;
}
select (fn) {
return new Enumerable(function * () {
for (const value of this) {
yield fn(value);
}
}.bind(this));
}
where (fn) {
return new Enumerable(function * () {
for (const value of this) {
if (fn(value)) yield value;
}
}.bind(this));
}
}
Object.setPrototypeOf(Array, Enumerable);
Object.setPrototypeOf(Array.prototype, Enumerable.prototype);
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const result = array
.select(v => v * 2)
.where(v => v % 3 === 0);
for (const item of result) {
console.log(item);
}
答案 2 :(得分:0)
如果您不介意过度扩展,则第一个迭代器仅返回一个对象。
您可以通过执行console.log(typeof arr.select(v => v * 2));
进行检查。
因此,您只需定义:Object.prototype.where = function* (fn) {};
Array.prototype.select = function* (fn) {
let it = this[Symbol.iterator]();
for (let item of it) {
yield fn(item);
}
};
Object.prototype.where = function* (fn) {
let it = this[Symbol.iterator]();
for (let item of it) {
if (fn(item)) yield item;
}
};
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
let result = arr.select(v => v * 2)
.where(v => v % 3 === 0);
for (let item of result) {
console.log(item);
}
如果您希望顺序无关紧要,则可以像这样扩展Array和Object。
Array.prototype.select = function* (fn) {
let it = this[Symbol.iterator]();
for (let item of it) {
yield fn(item);
}
};
Array.prototype.where = function* (fn) {
let it = this[Symbol.iterator]();
for (let item of it) {
if (fn(item)) yield item;
}
};
Object.prototype.select = Array.prototype.select;
Object.prototype.where = Array.prototype.where;
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
// Chain 1.
let result1 = arr.select(v => v * 2).where(v => v % 3 === 0);
console.log('Chain 1');
for (const item of result1) {
console.log(item);
}
// Chain 2.
let result2 = arr.where(v => v % 3 === 0).select(v => v * 2);
console.log('Chain 2')
for (const item of result2) {
console.log(item);
}