說說對 JavaScript 物件的理解
建立自定義物件的方式有兩種:
* 建立一個 Object 例項,然後再為它新增屬性和方法:
//建立 Object 的例項
var person = new Object();
person.name = "deniro";
person.age = 29;
person.job = "Software Engineer";
person.sayName = function () {
console.log(this.name);
};
- 物件字面量方式(已成為首選模式):
//物件字面量語法
var person = {
name: "deniro",
age: 29 ,
job: "Software Engineer",
sayName: function () {
console.log(this.name);
}
}
ECMA-262 第 5 版,定義了只有內部才能使用到的屬性,這些屬性是用於 JavaScript 引擎的實現上,因此 JavaScirpt 不能直接訪問到它們,它們一般用兩對方括號表示,比如[[Enumerable]]。
1 資料屬性
資料屬性包含一個數值的位置,在這個位置上可以讀取和寫入值。資料屬性有四個描述其行為的特性:
特性 | 說明 | 預設值 |
---|---|---|
[[Configurable]] | 能否通過 delete 刪除屬性 | true |
[[Enumerable]] | 能否通過 for-in 迴圈返回屬性 | true |
[[Writable]] | 能否修改屬性的值 | true |
[[Value]] | 包含這個屬性的資料值 | undefined |
var person = {
name: "deniro"
}
上面這個例子中的 name 屬性的 [[Value]] 被設定為 deniro,其他值設定為 true。
要修改屬性的預設特性,必須使用 ECMAScript 5 的 Object.defineProperty() 方法。它接受三個引數:屬性所在的物件,屬性名以及描述符物件。其中的描述符物件必須是 configurable、enumerable、writable 和 value:
var person = {};
Object.defineProperty(person, "name", {
writable: false,
value: "deniro"
});
console.log(person.name);//deniro
person.name = "Lily";
console.log(person.name);//deniro
一個屬性被設定為不可修改後,如果嘗試為它設定新值,在非嚴格模式下,會被忽略;在嚴格模式下,會丟擲錯誤。
把屬性設定為不可配置:
var person = {};
Object.defineProperty(person, "name", {
configurable: false,
value: "deniro"
});
console.log(person.name);//deniro
delete person.name;
console.log(person.name);//deniro
configurable 設定為 false,表示不能從物件中刪除屬性。如果這時對這個屬性呼叫 delete,在非嚴格模式下,會被忽略;在嚴格模式下,會丟擲錯誤。
一旦把屬性定義為不可配置(configurable 設定為 false),就不能再把它定義為可配置的了:
var person = {};
Object.defineProperty(person, "name", {
configurable: false,
value: "deniro"
});
//拋錯
Object.defineProperty(person, "name", {
configurable: true,
value: "deniro"
});
在呼叫 Object.defineProperty() 方法時,如果不指定,configurable、enumerable、writable 會預設為 false。多數情況下,沒有必要使用 Object.defineProperty() 方法,但理解這些概念有助於對於理解 JavaScript 物件。
注意: IE8 是第一個實現 Object.defineProperty() 的瀏覽器。然而這個版本的實現存在很多限制。因為實現的不徹底,所以建議大家不要在 IE8 中使用 Object.defineProperty()。
2 訪問器屬性
訪問器是一對 getter 和 setter 函式(非必須)。使用 getter 讀取訪問器屬性,使用 setter 寫入訪問器屬性。它有 4 個特性:
特性 | 說明 | 預設值 |
---|---|---|
[[Configurable]] | 能否通過 delete 刪除屬性 | true |
[[Enumerable]] | 能否通過 for-in 迴圈返回屬性 | true |
[[Get]] | 在讀取屬性時呼叫的函式 | undefined |
[[Set]] | 在寫入屬性時呼叫的函式 | undefined |
訪問器屬性必須使用 Object.defineProperty() 來定義:
var book = {
_year: 2016,
edition: 1
};
Object.defineProperty(book, "year", {
get: function () {
return this._year;
},
set: function (newValue) {
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2016;
}
}
});
book.year = 2017;
console.log(book.edition);//2
_year 前面的下劃線表示只能通過物件方法訪問的屬性。
使用訪問器的常見方式是,設定一個屬性的值會導致其他屬性值發生變化。
只指定 getter 表示屬性為只讀。在嚴格模式下,嘗試寫入會拋錯。只指定 setter 表示屬性為只寫。在非嚴格模式下,返回 undefined;在嚴格模式下,嘗試讀取會拋錯。
在不支援 ECMAScript 5 的瀏覽器中,一般有兩個非標準方法:__defineGetter__()
和__defineSetter__()
,這兩個方法會是由 Firefox 定義的,後來 Safari 3、Chrome 1、Opera 9.5 也給出了相同的實現。
下面用遺留的方法重寫了之前的例子:
var book = {
_year: 2016,
edition: 1
};
book.__defineGetter__("year", function () {
return this._year;
});
book.__defineSetter__("year", function (newValue) {
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2016;
}
});
book.year = 2017;
console.log(book.edition);//2
注意:在不支援 Object.defineProperty() 方法的瀏覽器中,不能修改 [[Configurable]] 和 [[Enumerable]]。
3 定義多個屬性
ECMAScript 5 定義的 Object.defineProperties(),可以一次定義多個屬性。它接受兩個引數(要新增和修改其屬性的物件、定義的屬性):
var book = {};
Object.defineProperties(book, {
_year: {
value: 2016
},
edition: {
value: 1
},
year: {
get: function () {
return this._year;
},
set: function () {
if (newValue > 2016) {
this._year = newValue;
this.edition += newValue - 2016;
}
}
}
});
4 讀取屬性的特性
ECMAScript 5 定義的 Object.getOwnPropertyDescriptor() ,會讀取屬性的特性。它接受兩個引數(屬性所在的物件、要讀取描述符的屬性名稱),返回值是物件,可能是訪問器屬性,也可能是資料屬性:
var book = {};
Object.defineProperties(book, {
_year: {
value: 2017
},
edition: {
value: 1
},
year: {
get: function () {
return this._year;
},
set: function (newValue) {
if (newValue > 2017) {
this._year = newValue;
this.edition += newValue - 2017;
}
}
}
});
var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
console.log(descriptor.value);//2017
console.log(descriptor.configurable);//false
console.log(typeof descriptor.get);//undefined
var descriptor = Object.getOwnPropertyDescriptor(book, "year");
console.log(descriptor.value);//undefined
console.log(descriptor.configurable);//false
console.log(typeof descriptor.get);//function
在支援 ECMAScript 5 版本的 JavaScript 中,可以針對任何物件(包括 DOM 和 BOM),使用 Object.getOwnPropertyDescriptor 方法。