【问题标题】:Javascript getter/setter scope access [duplicate]Javascript getter/setter 范围访问 [重复]
【发布时间】:2019-09-07 23:06:51
【问题描述】:

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

在下面的示例中,我想通过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() 应该都返回相同的结果。但相反,我收到了

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,它会评估它们。只需return 来自Counter 的对象文字。或者拨打Object.definePropertythis
  • 我不能返回对象字面量,因为那样的话,我会失去 this 的类型 Counter()。而且我相信以前的 getter/setter 问题没有我的问题的答案。为什么输出不一样?第二个属性counter.current -= 0.5 将值存储在哪里?
  • 你所说的“这个类型”是什么意思?反正你也不打算使用原型。
  • 关于您编辑的问题,counter.current 是一个简单的数据属性。您拨打的Object.assign(…)this.inc = inc; this.getCurrent = getCurrent; this.current = _current; // 0 的结果完全相同。 -= 0.5 赋值简单地将新数字存储在 counter 对象上。 incgetCurrent 仍然是内部 _current 变量的闭包。
  • 我的意思是get current() { … }, set current(…) { … },但是是的。当然这是一个普通的对象,但没关系,它具有您想要的所有功能。你为什么关心对象的类型,你需要它做什么?

标签: javascript properties getter-setter


【解决方案1】:

当您的代码调用Object.assign() 时,它会传入一个对象,该对象具有current 的getter 和setter。因此,Object.assign() 进程在将属性值复制到新对象时,本身将调用该 getter 以获取属性“current”的值。因此,Counter 对象最终没有 getter 和 setter,这解释了您的结果。它的“计数器”属性只是一个简单的属性,其中包含构造函数代码运行时本地 counter 变量的值的副本。

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

请注意,如果您根本不调用Object.assign(),而只是返回您传递给它的对象,您将获得一个行为与您预期一样的工作对象。

【讨论】:

  • 我相信在 Object.assign() 上还没有当前属性,只有一个当前 变量,我知道我正在混合两个对象,并且get/set 归第二个所有,但我仍然没有明白这一点。您能否指出另一种获得所需结果的方法?
  • @bittnkr 考虑一下Object.assign() 的作用:它在内部会执行类似Object.keys() 的操作来获取源对象的属性的names 列表,并在您的case "current" 是这些名称之一。当代码询问名为“current”的属性的值时,会发生什么?没错,您的 source 对象中的 getter 被调用,并返回 0。Object.assign() 不关心属性值来自 getter 函数。它只是在 target 对象上创建一个属性并将其值设为 0。
  • 好的。我知道 Object.assign() 在第一次调用 Object.assign() 时复制属性的值,而 不要 复制 getter/setter。之后对current 属性的所有访问都在此对象上作为普通属性进行,不再接触getter 或setter。看来Object.defineProperty() 是做我想做的唯一方法。
猜你喜欢
  • 1970-01-01
  • 2015-01-23
  • 2016-09-14
  • 1970-01-01
  • 2012-12-27
  • 2020-06-14
  • 2014-05-20
  • 2018-09-13
  • 2019-01-31
相关资源
最近更新 更多