Reputation: 2299
I was experimenting with some bits of code below and everything seems to be working as expected. The goal was to bind a.val
to b.val
such that when a.val
changed, b.val
would also change automatically.
// 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
So I wanted to move forward with this concept and abstract the Object.defineProperties
part into a function. I thought I could make a for loop and loop through the properties of one object, call Object.defineProperty
. But I ran into some issues:
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'
Essentially I have inadvertently bound the two properties of the object I was passing to the getSet
function. Furthermore I have erased their initial values.
My question is, why does that happen, and how do I get closer to my goal, of binding the properties of one object to another.
Through testing several other possible solutions I ran into a Maximum call stack size exceeded
error: I presume when referencing this
in the getter or setter, the act of getting the value from the object I am trying to define properties on triggers a call to the getter, and loops indefinitely. Not entirely sure when/why this happens.
Upvotes: 1
Views: 292
Reputation: 664548
Your current code doesn't really work. The two major flaws are
you cannot use arrow functions with this
in an object literal. The this
value will be the module object (in node) or global object (window
in browsers), not the current object.
a.val
from a.val
and write the value for a.val
to a.val
, creating the infinite recursion you experienced. You need to use something else for the actual storage - in your case, the b
object is the proper solution.name
property of the global object will coerce everything to a stringin your loop, there's only a single key
variable that the getter/setter functions close over. So all of them will use the value in the same place on the store.
To fix this, use
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;
}
Upvotes: 1