Reputation: 1681
Say I have an object instance like this :
var objectA = {"a": 1, "b": 2, "c" : 3};
and in my code I access the property like this:
cc.log(objectA.a); // output 1
now I want to add a get/set for this object to provide some simple encrypt/decrypt feature:
hookSetGet: function (someObject) {
for (var key in someObject) {
cc.log("key: " + key);
// store the origin value before Object.defineProperty
var pureValue = someObject[key];
// add a property to store the encrypted value
var hiddenValueKey = "__" + key;
someObject[hiddenValueKey] = undefined;
Object.defineProperty (
someObject,
key,
{
set: function (val) {
// simulate encrypt
this.hiddenValueKey = val + 1;
cc.log("hooked set: " + val + " - " + this.hiddenValueKey);
},
get: function () {
cc.log("hooked get: " + this.hiddenValueKey + " - " + (this.hiddenValueKey - 1));
// simulate decrypt
return this.hiddenValueKey - 1;
}
}
);
// trigger set to encrypt
someObject[key] = pureValue;
}
}
but when I test the function like this:
var objectA = {"a": 1, "b": 2, "c" : 3};
this.hookSetGet(objectA);
cc.log(objectA.a);
cc.log(objectA.b);
cc.log(objectA.c);
I do not get the result I want :
key: a
hooked set: 1 - 2
key: b
hooked set: 2 - 3
key: c
hooked set: 3 - 4
hooked get: 4 - 3
3
hooked get: 4 - 3
3
hooked get: 4 - 3
3
It seems like even when I call
objectA.a
I will get the value of
objectA.c
The problem seems quite simple but I just can not figure out where is wrong.
Any suggestion will be appreciated, thanks :)
UPDATE:
I tried the following code without change the code of hookSetGet :
cc.log(objectA.__a);
cc.log(objectA.__b);
cc.log(objectA.__c);
and get:
undefined
undefined
undefined
Then I changed the hookSetGet function:
set: function (val) {
// simulate encrypt
someObject[hiddenValueKey] = val + 1;
cc.log("hooked set: " + val + " - " + someObject[hiddenValueKey]);
},
get: function () {
cc.log("hooked get: " + someObject[hiddenValueKey] + " - " + (someObject[hiddenValueKey] - 1));
// simulate decrypt
return someObject[hiddenValueKey] - 1;
}
I changed all the this.hiddenValueKey to someObject[hiddenValueKey].
and the output is :
cc.log(objectA.__a); // 2 good
cc.log(objectA.__b); // 3 good
cc.log(objectA.__c); // 4 good
cc.log(objectA.a); // hooked get: 4 - 3 still wrong
cc.log(objectA.b); // hooked get: 4 - 3 still wrong
cc.log(objectA.c); // hooked get: 4 - 3 still wrong
Upvotes: 1
Views: 147
Reputation: 6560
There are several issues with your code. One of them is that key
and hiddenValueKey
are set in the scope of the hookGetSet
function. Therefore whenever you use them, you use the last value in the loop (3 and __c). You can fix this in two ways:
let
instead of var
to define key
and hiddenValueKey
within the loop scope, but that only works in ES6The other problem is that inside the properties you use this.hiddenValueKey, which is the same as this['hiddenValueKey']
, not this[hiddenValueKey]
as I assume you intended.
Here is code that works (EcmaScript6):
hookSetGet : function (someObject) {
for (let key in someObject) {
cc.log("key: " + key);
// store the origin value before Object.defineProperty
var pureValue = someObject[key];
// add a property to store the encrypted value
let hiddenValueKey = "__" + key;
someObject[hiddenValueKey] = undefined;
Object.defineProperty(
someObject,
key, {
set : function (val) {
// simulate encrypt
this[hiddenValueKey] = val + 1000;
cc.log("hooked set: " + val + " - " + this[hiddenValueKey]);
},
get : function () {
// simulate decrypt
var result = this[hiddenValueKey] - 1000;
cc.log("hooked get: " + this[hiddenValueKey] + " - " + result);
return result;
}
});
// trigger set to encrypt
someObject[key] = pureValue;
}
}
and here is same code for classic ES5 Javascript:
hookSetGet : function (someObject) {
for (var k in someObject) {
(function () {
var key = k;
cc.log("key: " + key);
// store the origin value before Object.defineProperty
var pureValue = someObject[key];
// add a property to store the encrypted value
var hiddenValueKey = "__" + key;
someObject[hiddenValueKey] = undefined;
Object.defineProperty(
someObject,
key, {
set : function (val) {
// simulate encrypt
this[hiddenValueKey] = val + 1000;
cc.log("hooked set: " + val + " - " + this[hiddenValueKey]);
},
get : function () {
// simulate decrypt
var result = this[hiddenValueKey] - 1000;
cc.log("hooked get: " + this[hiddenValueKey] + " - " + result);
return result;
}
});
// trigger set to encrypt
someObject[key] = pureValue;
})();
}
}
Upvotes: 0
Reputation: 28137
So, you wrote this:
Object.defineProperty (
someObject,
key,
{
set: function (val) {
// simulate encrypt
this.hiddenValueKey = val + 1;
cc.log("hooked set: " + val + " - " + this.hiddenValueKey);
},
get: function () {
cc.log("hooked get: " + this.hiddenValueKey + " - " + (this.hiddenValueKey - 1));
// simulate decrypt
return this.hiddenValueKey - 1;
}
}
);
In your getter and setter this
from this.hiddenValueKey
refers to your objectA
Object in all cases, not to each property. So when you want to set a value for each property you're actually over-writing objectA.hiddenValueKey
. This is why when you try to get
back the values you only get the last value which was set.
Even though you set hiddenValueKey
to be unique, in the getter and setter you acess the same property. This is because this.hiddenValueKey
is the same as writing this['hiddenValueKey']
. Did you mean to write this[hiddenValueKey]
? Even if you do it, you might have some scoping issues with the hiddenValueKey
always having the latest key value after you exit the loop.
So, you can try this:
Object.defineProperty (
someObject,
key,
{
set: function (val) {
// simulate encrypt
this[hiddenValueKey] = val + 1;
cc.log("hooked set: " + val + " - " + this[hiddenValueKey]);
},
get: function () {
cc.log("hooked get: " + this[hiddenValueKey] + " - " + (this[hiddenValueKey] - 1));
// simulate decrypt
return this[hiddenValueKey] - 1;
}
}
);
But, as I said, you might have to create a closure for the hiddenValueKey
variable so it will be unique for each property getter and setter.
You can create a closure like this:
(function(hiddenValueKey) {
Object.defineProperty (
someObject,
key,
{
set: function (val) {
// simulate encrypt
this[hiddenValueKey] = val + 1;
cc.log("hooked set: " + val + " - " + this[hiddenValueKey]);
},
get: function () {
cc.log("hooked get: " + this[hiddenValueKey] + " - " + (this[hiddenValueKey] - 1));
// simulate decrypt
return this[hiddenValueKey] - 1;
}
}
);
}(hiddenValueKey));
Upvotes: 1