我可以将 属性 附加到使用 JavaScript 中的函数*() 创建的生成器吗?

Can I attach a property to a generator created with function*() in JavaScript?

我正在寻找一种方法来公开使用 function*() 构造的生成器的其他属性。我尝试了两种幼稚的方法,但都没有达到我想要的效果。

方法 1 说明了我正在尝试做的事情,天真地尝试使用 this 将 属性 附加到生成器:

function* counter(startValue) {

  // trying to expose a property through "this", 
  // which does not work as intended 
  // (I actually expected this, but it illustrates what I am trying to do)
  this.startValue = startValue;

  // simple counter
  let currentValue = startValue;
  while (true) yield currentValue++;

}

// user code

let myCounter = counter(10);

console.log(myCounter.next().value);
// -> 10

console.log(myCounter.next().value);
// -> 11

// I want myCounter.startValue to expose the start value (10)
// unfortunately this does not work
console.log(myCounter.startValue);
// -> undefined

方法 2,尝试使用闭包来存储起始值:

// use a closure to store configuration & state
function counter(startValue) {
    let currentValue = startValue;
    let gen = function*() {
        while(true) yield currentValue++;
    }
    // Again, I want the generator to expose the "startValue" parameter
    // This also does not work:
    gen.startValue = startValue;
    return gen;
}

// user code

let myCounter = counter(10)();

myCounter.next().value;
// -> 10

myCounter.next().value;
// -> 11

// Again, no luck accessing the start value
myCounter.startValue;
// -> undefined

我想由于实际的生成器对象是由 JS 运行时隐式构造的,所以如果不创建某种包装对象就无法为其附加额外的属性?

(由于整个项目结构的原因,构建生成器然后附加 属性(myCounter.startValue = 10 在用户代码中的某处)对我来说不是一个选项,它必须完成在构造函数中)

你的关闭尝试是正确的方法,你只是错过了在函数内部创建生成器(你想附加 属性 ),而不是将它附加到生成器函数:

function* count(currentValue) {
    while(true) yield currentValue++;
}
function counter(startValue) {
    const gen = count(startValue);
    gen.startValue = startValue;
    return gen;
}

let myCounter = counter(10);

myCounter.next().value; // -> 10
myCounter.next().value; // -> 11

myCounter.startValue; // -> 10

正确的方法是通过它下面的实际内容来处理 ES6 生成器 - Iterable Iterator,并这样实现它,添加你的扩展:

function counter(startValue) {
    let currentValue = startValue;
    return {
        [Symbol.iterator]() {
            return this;
        },
        next() {
            return {value: currentValue++, done: false}
        },
        startValue
    };
}

let myCounter = counter(10);

console.log(myCounter.next().value); //=> 10

console.log(myCounter.next().value); //=> 11

console.log(myCounter.startValue); //=> 10

这就是正确扩展生成器的方式。