【问题标题】:Why does yielding a mutated object in a javascript generator result in different behavior when converted to array?为什么在转换为数组时在 javascript 生成器中生成变异对象会导致不同的行为?
【发布时间】:2020-01-28 15:29:13
【问题描述】:

我有一个用 JavaScript 编写的生成器函数foo

function* foo() {
    const bar = { a: 0, b: 0 };
    yield bar;

    bar.a += 1;
    yield bar;

    bar.b += 10;
    yield bar;
}

函数foo 不带参数,但保留一个用于产生的内部对象bar。该函数可以产生 3 次,每次返回不同的值。

在结果对象上调用 next().value 时会观察到预期的行为。

const baz = foo()
console.log(baz.next().value)   // => { a: 0, b: 0 }
console.log(baz.next().value)   // => { a: 1, b: 0 }
console.log(baz.next().value)   // => { a: 1, b: 10 } 

但是,当使用 Array.from 方法从生成的迭代器创建一个数组时,会观察到一个奇怪的行为。

console.log(Array.from(foo()))  // => [ { a: 1, b: 10 }, { a: 1, b: 10 }, { a: 1, b: 10 } ]

每次调用都会返回最终对象,而不是每次调用 yield 时都返回值!此行为发生在节点 10.13 和节点 12.7 中。为什么会这样?两种情况的结果不应该相同吗?

【问题讨论】:

  • 对象是通过引用传递的,所以最后你有一个数组,其中包含对同一对象的 3 个引用。
  • @NenadVracar 它在哪里通过引用传递?我好像看不到这里的路过。
  • 换句话说,你只创建一个对象,而不是三个。
  • @SebastianSimon 是的,但是 Array.from 方法不应该在每次调用 yield 时获得不同的值吗?
  • bar 的值引用了您正在修改的同一个对象{ a: 0, b: 0 },并且在每次产量时您都会产生bar

标签: javascript generator


【解决方案1】:

由于在 javascript 中对象是通过引用传递的,因此您在每次 yield 后都在修改同一个对象,最后您有一个数组,其中包含 3 个对最终状态下内存中同一对象的引用。

要获得包含不同对象的数组,您必须在每个产量上创建新对象,例如使用对象扩展语法。

function* foo() {
    let bar = { a: 0, b: 0 };
    yield bar;

    bar = {...bar, a: bar.a + 1}
    yield bar;
    
    bar = {...bar, b: bar.b + 10}
    yield bar;
}

const baz = foo()
console.log([...baz])

【讨论】:

    猜你喜欢
    • 2018-10-24
    • 2011-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-14
    • 1970-01-01
    相关资源
    最近更新 更多