如何使用作为生成器并能够链接它们的函数来扩展数组?

How to extend the array with functions that are generators and able to chain them?

如何使用 returns 生成器对象的函数扩展 Array 并能够链接它们?

我已经尝试扩展数组以查看是否可以链接生成器函数。第一个调用有效,但下一个链不会,因为它 returns 一个生成器对象,我不知道如何扩展它。

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);

如果你不介意过度扩展,第一个迭代器returns只是一个对象。 您可以通过 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);
}

您可以将这两个方法存储为 Object 的原型函数并移交迭代器对象,因为这两个函数都采用生成器和 returns 可迭代对象。

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);

在不修改 Object 的情况下,您仍然可以使用我创造的技术 .

使这些方法可链接

你首先定义你的基础 class,Array 将扩展它,然后你修改 Array 的原型链来人为地扩展你的基础 class。

请注意 select()where() 方法如何将您的原始生成器函数封装到 class 的 return 个新实例中,以便这些方法是可链接的。

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);
}