Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/382.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript Object.defineProperty get set返回错误的值_Javascript - Fatal编程技术网

Javascript Object.defineProperty get set返回错误的值

Javascript Object.defineProperty get set返回错误的值,javascript,Javascript,假设我有这样一个对象实例: var objectA = {"a": 1, "b": 2, "c" : 3}; 在我的代码中,我访问属性的方式如下: cc.log(objectA.a); // output 1 var objectA = {"a": 1, "b": 2, "c" : 3}; this.hookSetGet(objectA); cc.log(objectA.a); cc.log(objectA.b); cc.log(objectA.c); (function(hidd

假设我有这样一个对象实例:

var objectA = {"a": 1, "b": 2, "c" : 3};
在我的代码中,我访问属性的方式如下:

cc.log(objectA.a); // output 1
var objectA = {"a": 1, "b": 2, "c" : 3};
this.hookSetGet(objectA);

cc.log(objectA.a);
cc.log(objectA.b);
cc.log(objectA.c);
   (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));
现在,我想为该对象添加一个get/set,以提供一些简单的加密/解密功能:

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;
    }
}
但是当我像这样测试函数时:

cc.log(objectA.a); // output 1
var objectA = {"a": 1, "b": 2, "c" : 3};
this.hookSetGet(objectA);

cc.log(objectA.a);
cc.log(objectA.b);
cc.log(objectA.c);
   (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));
我没有得到我想要的结果:

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
甚至当我打电话的时候

objectA.a
我将得到的价值

objectA.c
这个问题似乎很简单,但我就是想不出哪里错了

如有任何建议,将不胜感激,谢谢:)

更新:

我尝试了以下代码,但没有更改hookSetGet的代码:

cc.log(objectA.__a);
cc.log(objectA.__b);
cc.log(objectA.__c);
并获得:

undefined
undefined
undefined
然后我更改了hookSetGet函数:

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;
}
我将所有this.hiddenValueKey更改为someObject[hiddenValueKey]

输出为:

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
所以,你写了这个:

   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;
            }
        }
    );
在您的getter和setter
中,this
from
this.hiddenValueKey
在所有情况下都引用您的
对象a
对象,而不是每个属性。因此,当您想要为每个属性设置一个值时,实际上是在重写
objectA.hiddenValueKey
。这就是为什么当您尝试
获取
返回值时,您只能获取最后设置的值

即使将
hiddenValueKey
设置为唯一,在getter和setter中也可以访问相同的属性。这是因为
This.hiddenValueKey
与编写
This['hiddenValueKey']
相同。你是想写这个[hiddenValueKey]?即使这样做,退出循环后,
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
变量创建一个闭包,以便它对于每个属性getter和setter都是唯一的

可以创建如下所示的闭包:

cc.log(objectA.a); // output 1
var objectA = {"a": 1, "b": 2, "c" : 3};
this.hookSetGet(objectA);

cc.log(objectA.a);
cc.log(objectA.b);
cc.log(objectA.c);
   (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));

您的代码有几个问题。其中之一是在
hookGetSet
函数的范围内设置
key
hiddenValueKey
。因此,无论何时使用它们,都会使用循环中的最后一个值(3和__c)。您可以通过两种方式解决此问题:

  • 使用
    let
    而不是
    var
    在循环范围内定义
    key
    hiddenValueKey
    ,但这仅适用于ES6
  • 使用闭包来确定循环内部的范围
另一个问题是在属性内部使用this.hiddenValueKey,它与
this['hiddenValueKey']
相同,而不是
我假设您想要的这个[hiddenValueKey]

以下是有效的代码(ECMAScript 6):

下面是与经典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;
        })();
    }
}

在枚举对象时修改对象是否明智?@MatthewHerbst:是的,这不重要,属性不会重复两次。可能重复,谢谢你的帮助:)现在一切正常:)