Javascript getter/setter 范围访问

Javascript getter/setter scope access

我正在尝试使用具有 classic 原型继承的 JS,而不是新的 ES6 class 模型,主要是为了能够访问闭包范围。

在下面的示例中,我想通过 new 运算符创建的 this 对象公开函数 Counter 中声明的变量 current

function Counter(start, stop) {
  var current = start;

  function inc() { if (current < stop) return current++ }

  function getCurrent() { return current }

  Object.assign(this, { inc, getCurrent,
    get current() { return current }, set current(value) { current = value }
  })
}

counter = new Counter(0, 3)

while ((v = counter.inc()) !== undefined)
   console.log(counter.getCurrent(), counter.current)

我期望得到以下输出:

1 1 
2 2
3 3

因为 counter.currentcounter.getCurrent() 应该 return 相同的结果。但相反,我收到

1 0 
2 0
3 0

如果我用下面的代码替换 Object.assign(...),它会按预期工作。

  Object.assign(inc, getCurrent })
  Object.defineProperty(Counter.prototype, 'current',
    { get: () => { return current }, set: (value) => { current = value } 

我可以使用这个模型,(目前正在使用),但我想使用前者,因为它更简单,也不那么冗长。好像这里有2个不同的作用域。

我用节点 10、Chrome 73 和 Firefox 68 进行了测试,得到了相同的结果。

我在这里缺少什么?


在上面的示例中,我尽量做到简洁。但为了更准确和更好地说明这一点,请遵循更完整的测试,并附上我尝试过的一些评论。

在这里,我将变量 current 重命名为 _current 以避免与 current 属性 混淆,但这不是强制性的。


function Counter(start, stop) {
  var _current = start;
  function inc() { if (_current < stop) return _current++ }
  function getCurrent() { return _current }

  // Object.assign(this.constructor.prototype,
  // Object.assign(this.__proto__,
  // Object.assign(Counter.prototype, {

  Object.assign(this, {inc, getCurrent,
    get current() { return _current }, set current(value) { _current = value }
    // get current() { return current } // supposed to be read-only, but not
  })

  // This works as expected
  // Object.defineProperty(Counter.prototype, 'current',
  //   { get: () => { return _current }, set: (value) => { _current = value } })
}

counter = new Counter(0, 3)

while ((v = counter.inc()) !== undefined) {
  console.log(counter.getCurrent(), counter.current)
  counter.current -= 0.5
}

上面代码的输出是:

1 0
2 -0.5
3 -1

counter.current -= 0.5 在哪里存储它的值?

当您的代码调用 Object.assign() 时,它会传入一个对象,该对象具有 getter 和 setter 用于 current。因此,在将 属性 值复制到新对象时,Object.assign() 进程本身将调用 getter 来获取 属性 "current" 的值。因此,计数器对象最终 没有 getter 和 setter,这解释了您的结果。它的 "counter" 属性 只是一个简单的 属性,带有构造函数代码 运行.[=16 时局部 counter 变量值的副本=]

Object.assign() 只是复制 属性 值,以与任何其他代码相同的方式访问它们。

请注意,如果您 根本不 调用 Object.assign(),而只是 return 您传递给它的对象,您将得到一个像你期望的那样工作的对象。