2011-08-30 66 views
0

我試圖在程序getter/setter方法添加到JavaScript中的對象,雖然我覺得下面的代碼應該簡單的工作,如我所料不採取行動。如何程序設置Javascript getter/setters? (或實際關閉範圍)

這裏是我的代碼:

var data = {a:1, b:2, c:3}; 
function Abc(data) { 
    var data = data || {}; 
    for (var key in data) { 
     console.log(key, data[key]); 
     this.__defineGetter__(key, function() { 
       console.log('using getter'); 
       return data[key]; 
      }) 
    } 
    return this; 
} 

abc = Abc(data); 
console.log('this should be 1', abc.a); 
console.log('this should be 2', abc.b); 
console.log('this should be 3', abc.c); 

,這是我意想不到的輸出

a 1 
b 2 
c 3 
using getter 
this should be 1 3 
using getter 
this should be 2 3 
using getter 
this should be 3 3 

輸出使得完全沒有意義的我,但我得到在Chrome和Webkit相同的輸出,所以我猜我只是愚蠢的,這不是一個Javascript引擎的錯誤:)


作爲公司米特斯提到我對「數據」的三重使用並不是很好!

+0

做;'? – sje397

+0

嘗試在'console.log'中放入更多診斷以包含密鑰。關閉只有一個我認爲的關鍵。 –

+0

對於初學者來說,當你有三個不同的範圍變量時,你會混淆自己,所有的變量名都是'data'。我首先給出所有這三個(全局'data',函數參數'data'和局部變量'data')的不同名稱。您在該功能中阻止訪問其中的兩個,因此您可能無法獲得您期望的內容。 – jfriend00

回答

1

@Robert古爾德。代碼示例中的主要問題不在於「定義getter和setter」,而在於「理解閉包」。

Additionaly你的代碼是使用關鍵字無效的,因爲你的農行()函數對象指向全球窗口對象。您必須使用新的Abc()正確使用這個關鍵字或必須在Abc()中創建新的空對象並返回它。

1)

function Abc(data) { 
    data=data||{}; 
    for(key in data) { 
    console.log(key, data[key]); 
    (function(data,key) { // defining closure for our getter function 
     this.__defineGetter__(key, function() { 
       console.log('using getter'); 
       return data[key]; 
      }); 
    }).call(this,data,key); 
    } 
    // dont need to return: when used *new* operator *this* is returned by default 
} 
var abc = new Abc(data); 

或 2)

function Abc(data) { 
    data=data||{}; 
    var obj={}; 
    for(key in data) { 
    console.log(key, data[key]); 
    (function(data,key) { // defining closure for our getter function 
     obj.__defineGetter__(key, function() { 
       console.log('using getter'); 
       return data[key]; 
      }); 
    })(data,key); 
    } 
    return obj; // return object 
} 
var abc = Abc(data); 

如果你真的需要知道關於 「定義干將| setterns」 閱讀:

+0

謝謝你的鏈接! –

+0

@Robert Gould - 您可以將我的示例與代碼_if(!(this instance of Abc)){return new Abc(data);如果需要,並且原型繼承很重要,由** icktoofay **提供。 –

3

在執行到__defineGetter__的關閉時,循環結束並且key保持最後的值。試試這個:

function Abc(data) { 
    if(!(this instanceof Abc)) { 
     return new Abc(data); 
    } 
    data = data || {}; 
    for(var key in data) { 
     (function(key) { 
      console.log(key, data[key]); 
      this.__defineGetter__(key, function() { 
       console.log('using getter'); 
       return data[key]; 
      }); 
     }).call(this, key); 
    } 
    return this; 
} 

一些其他的事情:

  1. 你不是在key使用var,所以key是全球性的。這不會導致你的問題,但無論如何,添加它是個好主意。
  2. 你被聲明名爲data時,我們已經有功能的範圍data新的變量。因爲函數中已經有一個data,所以不需要在那裏使用var;我刪除它。
  3. 你沒有使用new,這也是導致古怪的行爲;函數頂部的新三行導致它像使用new調用一樣。
+0

這個工程!我有種想象中的Javascript閉包比這更堅實,但它完成了工作!謝謝 –

1

key是Abc範圍內的局部變量,所寫的匿名函數沒有可變關鍵字,所以它使用了外部作用域中的一個。在使用匿名函數時,該變量已更改爲循環中的最後一個值,因此您會看到最後一個值。您可以通過關閉解決這個問題:

this.__defineGetter__(key, (function(l_key){ 
    return function() { 
     console.log('using getter'); 
     return data[l_key]; 
    } 
})(key)); 

在該代碼中l_keykey本地副本匿名函數返回的是另一個匿名函數。

+0

謝謝你的例子,現在我明白了發生了什麼! –