Javascript Object.defineProperty复制属性值

Javascript Object.defineProperty复制属性值,javascript,this,getter-setter,Javascript,This,Getter Setter,我正在试验下面的一些代码,一切似乎都按预期进行。目标是将a.val绑定到b.val,这样当a.val更改时,b.val也会自动更改 // instantiate var a = {} var b = {} // set value a.val = 10 // check values console.log("A.val is:", a.val) // 10 console.log("B.val is:", b.val) // undefined // bind values Objec

我正在试验下面的一些代码,一切似乎都按预期进行。目标是将
a.val
绑定到
b.val
,这样当
a.val
更改时,
b.val
也会自动更改

// instantiate 
var a = {}
var b = {}

// set value
a.val = 10

// check values
console.log("A.val is:", a.val) // 10
console.log("B.val is:", b.val) // undefined

// bind values
Object.defineProperties(a, {
  val: {
    configurable: true, // can be changed or deleted
    enumerable: true,   // can be iterated over
    get: ()=> this.val,
    set: (value)=> {
        this.val = value
        b.val = value
        return value
    }
  }
})

// reset value
a.val = 20

// check values
console.log("A.val is:", a.val) // 20
console.log("B.val is:", b.val) // 20
所以我想继续这个概念,并将
对象.defineProperties
部分抽象为一个函数。我想我可以通过一个对象的属性创建一个for循环和循环,调用
object.defineProperty
。但我遇到了一些问题:

function getSet(props){
  for(var key in props){
    Object.defineProperty(props, key, {
      configurable: true, // can be changed or deleted
      enumerable: true,   // can be iterated over
      get: ()=> this[key],
      set: (value)=> {
          this[key] = value
          return value
      }
    })
  }

  return props
}

var a = getSet({name: 'the letter a', age: 12})

a.name // undefined
a.name = 'the letter a'
a.age // 'the letter a'
实际上,我无意中绑定了传递给
getSet
函数的对象的两个属性。此外,我还删除了它们的初始值

我的问题是,为什么会发生这种情况,以及我如何更接近我的目标,将一个对象的属性绑定到另一个对象


通过测试其他几种可能的解决方案,我遇到了一个
超过最大调用堆栈大小的
错误:我假设在getter或setter中引用
this
时,从我试图定义属性的对象获取值的行为会触发对getter的调用,并无限期地循环。不完全确定发生这种情况的时间/原因。

您当前的代码实际上无法工作。这两个主要缺陷是

  • 你。
    值将是模块对象(在节点中)或全局对象(
    浏览器中的窗口
    ),而不是当前对象

    • 如果它按照您的预期工作,并且引用了当前访问的接收者(这也是在您尝试适当的方法时发生的),那么您将从
      a.val
      读取
      a.val
      的值,并将
      a.val
      的值写入
      a.val
      ,从而创建您所经历的无限递归。您需要为实际存储使用其他东西-在您的情况下,
      b
      对象是正确的解决方案
    • 在浏览器中,指定给全局对象的
      name
      属性将强制所有内容为字符串
  • 在你的循环中,只有一个循环。因此,它们都将在商店的同一位置使用该值

要解决此问题,请使用

function getSet(proxy, store) {
  for (const key in store) {
//     ^^^^^ block scope
    Object.defineProperty(props, key, {
      configurable: true,
      enumerable: true,
      get: () => { return store[key]; },
//                        ^^^^^
      set: (value) => { store[key] = value; }
//                      ^^^^^
    });
  }
  return proxy;
}

与您认为的功能无关。在你的
getSet
函数
中,这个
指的是窗口。@Tibrogargan:你说得对。虽然。这并不能完全解决我的问题。我用
var copy=Object.assign({},props)
实现了同样的功能,并用
copy
替换了
this
。这些属性仍然受到约束。如果我改变
年龄
它会改变
姓名
,反之亦然。