來自John Resig早年的文章,大致翻譯了一下,以作備忘。
令人高興的是,我想我終於可以說,“現在,JavaScript的Getters和Setters使用非常廣泛,它和每個JavaScript開發人員的切身利益息息相關”。靠,我為了說這句話已經等了很久了。
首先,我們先來快速瞭解什麼是Getters和Setters,以及它們為什麼很有用。然後,我們來看看現在都有哪些平台支援Gettets和Setters。
Getters和Setters
Getters和Setters使你可以快速擷取或設定一個對象的資料。一般來說,一個對象擁有兩個方法,分別用於擷取和設定某個值,比如:
複製代碼 代碼如下:{
getValue: function(){
return this._value;
},
setValue: function(val){
this._value = val;
}
}
用這種方式寫JavaScript的一個明顯的好處是:你可以用它來隱藏那些不想讓外界直接存取的屬性。最終的代碼看起來就像下面這樣(用閉包儲存新建立的Filed對象的value): 複製代碼 代碼如下:function Field(val){
var value = val;
this.getValue = function(){
return value;
};
this.setValue = function(val){
value = val;
};
}
於是我們可以這樣使用: 複製代碼 代碼如下:var field = new Field("test");
field.value
// => undefined
field.setValue("test2")
field.getValue()
// => "test2"
我們來類比上例中的 “隱藏的value屬性”,我們的代碼就像這樣: 複製代碼 代碼如下:function Field(val){
var value = val;
this.__defineGetter__("value", function(){
return value;
});
this.__defineSetter__("value", function(val){
value = val;
});
}
但是呢,你不喜歡這樣寫,而傾向在對象的prototype中定義getters和setters(私人變數寫在哪並不重要),我們可以用另一種文法。 複製代碼 代碼如下:function Field(val){
this.value = val;
}
Field.prototype = {
get value(){
return this._value;
},
set value(val){
this._value = val;
}
};
這種文法看起來很不可思議,但是使用過一段時間之後,接受它也很容易。
接下來是另一個例子,它允許外界擷取一個username數組,但是卻不能擷取原始的,隱藏的user對象。 複製代碼 代碼如下:function Site(users){
this.__defineGetter__("users", function(){
// JS 1.6 Array map()
return users.map(function(user){
return user.name;
});
};
}
作為福利,我寫了一個方法,它可以幫你實現對象的繼承,並且還考慮到了getters和setters 複製代碼 代碼如下:// Helper method for extending one object with another
function extend(a,b) {
for ( var i in b ) {
var g = b.__lookupGetter__(i), s = b.__lookupSetter__(i);
if ( g || s ) {
if ( g )
a.__defineGetter__(i, g);
if ( s )
a.__defineSetter__(i, s);
} else
a[i] = b[i];
}
return a;
}
在我的extend()方法中,你會發現兩個新方法:__lookupGetter__和__lookupSetter__。一旦你真正開始使用getters和setters,這將很有用。
比如,當我第一次寫extend()方法時,我遇到了各種errors,我徹底暈了。後來我發現問題就出在一個簡單的語句上:a[i] = b[i];
如果對象a存在一個setter,名字叫做i,對象b存在一個getter,名字也叫做i,a[i]不是通過別的setter方法賦值的,而是來自b的getter方法。這兩個__lookup*__方法使你可以擷取原始的函數。(這段翻得有點晦澀,原文如下)
If a setter existed in object a, named i, and a getter existed in object b, named i, a[i]'s value was being set not to the other setter function, but to the computed value from b's getter function. The two __lookup*__ methods allow you to access the original functions used for the methods (thus allowing you to write an effective extend method, for example).
記住以下幾點:
一個對象內,每個變數只能有一個getter或setter。(因此value可以有一個getter和一個setter,但是value絕沒有兩個getters)
刪除getter或setter的唯一方法是:delete object[name]。delete可以刪除一些常見的屬性,getters和setters。
如果使用__defineGetter__或__defineSetter__,它會重寫之前定義的相同名稱的getter或setter,甚至是屬性(property)。
平台
支援的瀏覽器有:
Firefox
Safari 3+
Opera 9.5
(原文沒寫Chrome,還沒出呢)
我用下面的代碼測試瀏覽器: 複製代碼 代碼如下:javascript:foo={get test(){ return "foo"; }};alert(foo.test);
另外,以下兩種引擎也支援Getters和Setters:
SpiderMonkey
Rhino 1.6R6 (New)