2016-04-13 48 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));