程式在執行物件屬性訪問(property accesses)時有一個的細節。比方說 obj.a
並不只是找到一個 obj
物件,然後取得它的 a
屬性,它實際上調用了一個內建函式,並依照某些特定條件執行。
undefined
。var obj = {
a: undefined
};
console.log(obj.a); // undefined
console.log(obj.b); // undefined
以上程式碼內,從結果上來說查詢 obj.a
和 obj.b
同樣返回 undefined
,但在底層的操作中,查詢 obj.b
實際多了一些處理步驟。
除此之外,物件屬性查找與變數查找的一個明顯不同是,作用域內如果找不到變數,會返回 ReferenceError
,但物件屬性查找不會出現 ReferenceError
,而是在失敗後返回一個 undefined
。
與屬性訪問相同,物件在修改屬性時,同樣會調用一個內部的函式,並根據屬性是否已經存在,表現出不同行為。
setter
,如果是,就調用這個 setter
。writable
為 false
這個屬性描述符,在非嚴格模式下無聲地失敗,在嚴格模式下則拋出一個 TypeError
以下就來介紹訪問描述器(accessor descriptor)。在 ES5 以後出現的屬性描述符,可以替屬性設置 get
與 set
,分別可以看做是這個屬性的取值器(getter)與設值器(setter)。
get
與 set
的內容都是一個函式,前者會在對屬性取值時被調用,後者會在屬性設值時被調用。
它們可以藉由字面值定義,也可以使用 Object.defineProperty
定義:
var obj = {
get a() {
return 2;
}
};
Object.defineProperty(
obj,
"b",
{
get: function () { return this.a * 2 },
}
);
console.log(obj.a); // 2
console.log(obj.b); // 4
console.log(Object.getOwnPropertyDescriptor(obj, "b"));
// {
// get: [Function: get],
// set: undefined,
// enumerable: false,
// configurable: false
// }
設置取值器後,訪問該屬性會自動調用取值器函式,函式返回的值就是屬性訪問獲得的結果:
var obj = {
get a() {
return 2;
}
};
obj.a = 3;
obj.a; // 2
以上程式碼中,將 obj.a
重新賦值並不會報錯,只會讓賦值無聲地失敗。所以大多時候,我們會同時設置取值器與設值器,只有他們單一任一個經常會導致非預期的結果。
設置取值器與設值器的範例:
var obj = {
get a() {
return this.privateProp;
},
set a(val) {
this.privateProp = val * 2;
}
};
obj.a = 2;
console.log(obj.a); // 4
在上面的程式碼中,我們利用了 this
的隱含綁定設置 privateProp
這個屬性,並在取值和設值時訪問該屬性。
屬性的描述符風格只能在資料描述符與訪問描述符中則一,如果一個屬性設置了 get
或 set
或兩者都有,它便不能同時具備 writable
或 value
描述符,否則會拋出 TypeError
:
var obj = {};
Object.defineProperty(obj, "prop1",
{
get: function () { return 2; },
writable: false,
}
);
// TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute