2016-04-13 32 views
2

说我有一个这样的对象实例:Object.defineProperty得到集中返回错误值

var objectA = {"a": 1, "b": 2, "c" : 3}; 

,并在我的代码访问属性是这样的:

cc.log(objectA.a); // output 1 

现在我要添加一个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; 
    } 
} 

但是当我测试这样的函数时:

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

cc.log(objectA.a); 
cc.log(objectA.b); 
cc.log(objectA.c); 

我没有得到的结果,我想:

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 

值这个问题似乎很简单,但我不能无花果排除哪里出错。

任何建议将赞赏,感谢:)

UPDATE:

我试着下面的代码,而无需改变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 
+0

是否明智,而你是列举了它来修改一个对象? –

+0

@MatthewHerbst:是的,这应该不重要,属性永远不会迭代两次。 – Bergi

+0

[点符号与括号表示法]的可能重复(https://stackoverflow.com/questions/4968406/javascript-property-access-dot-notation-vs-brackets)和[JavaScript闭环内循环](http:// stackoverflow.com/q/750486/1048572) – Bergi

回答

0

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

  • 使用let代替var到环路范围内定义keyhiddenValueKey,但只有在ES6
  • 作品使用闭包范围内环路内侧

另一个问题是,在您使用this.hiddenValueKey的属性内,这与this['hiddenValueKey']相同,而不是this[hiddenValueKey],因为我认为您的意图。

这里是代码,工程(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; 
    } 
} 

,这里是经典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; 
     })(); 
    } 
} 
+0

感谢您的帮助:)现在一切工作正常:) – supersuraccoon

1

所以,你写这样的:从this.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; 
      } 
     } 
    ); 

在您的getter和setter this指的是你objectA对象在任何情况下,不要每个属性。所以当你想为每个物业设定一个价值时,你实际上是在写​​。这就是为什么当你尝试get返回值时,你只能得到最后设定的值。

尽管您将hiddenValueKey设置为唯一,但在getter和setter中您获得了相同的属性。这是因为this.hiddenValueKey与编写this['hiddenValueKey']相同。你的意思是写this[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独特。

您可以创建一个闭包是这样的:

(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));