1.定義構造函數的兩種方式###
// # 1.創建自定義對象的最簡單方式就是創建一個 Object 的實例#
var person = new Object();
person.name = "Nicholas";
person.age = 29;
person.job = "Software Engineer";
person.sayName = function(){
alert(this.name);
};
// 2. 對象對象字面量
var person = {
name: "Nicholas",
age: 29,
job: "Software Engineer",
sayName: function(){
alert(this.name);
}
};
2.屬性類型
ECMAScript 中有兩種屬性:數據屬性和訪問器屬性。
1. 數據屬性####
[[Configurable]]:表示能否通過 delete 刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問器屬性。像前面例子中那樣直接在對象上定義的屬性,它們的這個特性默認值為 true。
[[Enumerable]]:表示能否通過 for-in 循環返回屬性。像前面例子中那樣直接在對象上定義的屬性,它們的這個特性默認值為 true。
[[Writable]]:表示能否修改屬性的值。像前面例子中那樣直接在對象上定義的屬性,它們的這個特性默認值為 true。
[[Value]]:包含這個屬性的數據值。讀取屬性值的時候,從這個位置讀;寫入屬性值的時候,把新值保存在這個位置。這個特性的默認值為 undefined。
對于像前面例子中那樣直接在對象上定義的屬性,它們[[Configurable]]、 [[Enumerable]]和[[Writable]]特性都被設置為 true,而[[Value]]特性被設置為指定的值。例如:
var person = {
name: "Nicholas"
};
注意: 這里創建了一個名為 name 的屬性,為它指定的值是"Nicholas"。也就是說, [[Value]]特性將被設置為"Nicholas",而對這個值的任何修改都將反映在這個位置。
- 要修改屬性默認的特性,必須使用 ECMAScript 5 Object.defineProperty()方法。這個方法接收三個參數:屬性所在的對象、屬性的名字和一個描述符對象。其中,描述符(descriptor)對象的屬性必須是: configurable、 enumerable、 writable 和 value。設置其中的一或多個值,可以修改對應的特性值。例如:
var person = {};
Object.defineProperty(person, "name", {
writable: false, // ** 表示只讀 **
value: "Nicholas"
});
alert(person.name); //"Nicholas"
person.name = "Greg";
alert(person.name); //"Nicholas"
** 分析:** * 這個例子創建了一個名為 name 的屬性,它的值"Nicholas"是只讀的。這個屬性的值是不可修改的,如果嘗試為它指定新值,則在非嚴格模式下,賦值操作將被忽略;在嚴格模式下,賦值操作將會導致拋出錯誤。*
類似的規則也適用于不可配置的屬性。例如:
var person = {};
Object.defineProperty(person, "name", {
configurable: false, //表示不能刪除
value: "Nicholas"
});
alert(person.name); //"Nicholas"
delete person.name;
alert(person.name); //"Nicholas"
注意: 把 configurable 設置為 false,表示不能從對象中刪除屬性。如果對這個屬性調用 delete,則在非嚴格模式下什么也不會發生,而在嚴格模式下會導致錯誤。而且,一旦把屬性定義為不可配置的,就不能再把它變回可配置了。此時,再調用 Object.defineProperty()方法修改除 writable 之外的特性,都會導致錯誤:
var person = {};
Object.defineProperty(person, "name", {
configurable: false,
value: "Nicholas"
});
//拋出錯誤
Object.defineProperty(person, "name", {
configurable: true,
value: "Nicholas"
});
注意:
1.也就是說,可以多次調用 Object.defineProperty()方法修改同一個屬性,但在把 configurable特性設置為 false 之后就會有限制了。
2.在調用 Object.defineProperty()方法時,如果不指定, configurable、 enumerable 和writable 特性的默認值都是 false。多數情況下,可能都沒有必要利用 Object.defineProperty()方法提供的這些高級功能。不過,理解這些概念對理解 JavaScript 對象卻非常有用。
2. 訪問器屬性
** 訪問器屬性不包含數據值;它們包含一對兒 getter 和 setter 函數(不過,這兩個函數都不是必需的)。在讀取訪問器屬性時,會調用 getter 函數,這個函數負責返回有效的值;在寫入訪問器屬性時,會調用setter 函數并傳入新值,這個函數負責決定如何處理數據。訪問器屬性有如下 4 個特性。**
1 . [[Configurable]]:表示能否通過 delete 刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為數據屬性。對于直接在對象上定義的屬性,這個特性的默認值為true。
2 . [[Enumerable]]:表示能否通過 for-in 循環返回屬性。對于直接在對象上定義的屬性,這個特性的默認值為 true。
3 . [[Get]]:在讀取屬性時調用的函數。默認值為 undefined。
4 . [[Set]]:在寫入屬性時調用的函數。默認值為 undefined。
var book = {
_year: 2004,
edition: 1
};
Object.defineProperty(book, "year", {
get: function(){ //讀取屬性時調用的函數。
return this._year;
},
set: function(newValue){ //寫入屬性時調用的函數
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
});
book.year = 2005; //這是寫入的時候。
alert(book.edition); //2
解釋: 以上代碼創建了一個 book 對象,并給它定義兩個默認的屬性: _year 和 edition。 _year 前面的下劃線是一種常用的記號,用于表示只能通過對象方法訪問的屬性。而訪問器屬性 year 則包含一個getter 函數和一個 setter 函數。 getter 函數返回_year 的值, setter 函數通過計算來確定正確的版本。因此,把 year 屬性修改為 2005 會導致_year 變成 2005,而 edition 變為 2。這是使用訪問器屬性的常見方式,即設置一個屬性的值會導致其他屬性發生變化。
注意:不一定非要同時指定 getter 和 setter。只指定 getter 意味著屬性是不能寫,嘗試寫入屬性會被忽略。在嚴格模式下,嘗試寫入只指定了 getter 函數的屬性會拋出錯誤。類似地,只指定 setter 函數的屬性也不能讀,否則在非嚴格模式下會返回 undefined,而在嚴格模式下會拋出錯誤。
特殊情況:
/支持 ECMAScript 5 的這個方法的瀏覽器有 IE9+(IE8 只是部分實現)、 Firefox 4+、 Safari 5+、 Opera
12+ 和 Chrome 。 在 這 個 方 法 之 前 , 要 創 建 訪 問 器 屬 性 , 一 般 都 使 用 兩 個 非 標 準 的 方 法 :
defineGetter()和defineSetter()。這兩個方法最初是由 Firefox 引入的,后來 Safari 3、
Chrome 1 和 Opera 9.5 也給出了相同的實現。使用這兩個遺留的方法,可以像下面這樣重寫前面的例子。/
var book = {
_year: 2004,
edition: 1
};
//定義訪問器的舊有方法
book.__defineGetter__("year", function(){
return this._year;
});
book.__defineSetter__("year", function(newValue){
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
});
book.year = 2005;
alert(book.edition); //2
3.定義多個屬性##
由于為對象定義多個屬性的可能性很大, ECMAScript 5 又定義了一個 Object.defineProperties()方法。利用這個方法可以通過描述符一次定義多個屬性。這個方法接收兩個對象參數:第一個對象是要添加和修改其屬性的對象,第二個對象的屬性與第一個對象中要添加或修改的屬性一一對
應。例如:
var book = {};
Object.defineProperties(book, {
_year: {
value: 2004
},
edition: {
value: 1
},
year: {
get: function(){
return this._year;
},
set: function(newValue){
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
});
解釋: 以上代碼在 book 對象上定義了兩個數據屬性(_year 和 edition)和一個訪問器屬性(year)。最終的對象與上一節中定義的對象相同。唯一的區別是這里的屬性都是在同一時間創建的。
版本: *支持 Object.defineProperties()方法的瀏覽器有 IE9+、 Firefox 4+、 Safari 5+、 Opera 12+和
Chrome。
4.讀取屬性的特性##
使用 ECMAScript 5 的 Object.getOwnPropertyDescriptor()方法,可以取得給定屬性的描述符。這個方法接收兩個參數:屬性所在的對象和要讀取其描述符的屬性名稱。返回值是一個對象,如果是訪問器屬性,這個對象的屬性有 configurable、 enumerable、 get 和 set;如果是數據屬性,這個對象的屬性有 configurable、 enumerable、 writable 和 value。例如:
var book = {};
Object.defineProperties(book, {
_year: {
value: 2004
},
edition: {
value: 1
},
year: {
get: function(){
return this._year;
},
set: function(newValue){
if (newValue > 2004) {
this._year = newValue;
this.edition += newValue - 2004;
}
}
}
});
var descriptor = Object.getOwnPropertyDescriptor(book, "_year");
alert(descriptor.value); //2004
alert(descriptor.configurable); //false
alert(typeof descriptor.get); //"undefined"
var descriptor = Object.getOwnPropertyDescriptor(book, "year");
alert(descriptor.value); //undefined
alert(descriptor.enumerable); //false
alert(typeof descriptor.get); //"function"
解釋: 對于數據屬性_year, value 等于最初的值, configurable 是 false,而 get 等于 undefined。對于訪問器屬性 year, value 等于 undefined, enumerable 是 false,而 get 是一個指向 getter函數的指針。
** 版本(使用范圍):在 JavaScript 中,可以針對任何對象——包括 DOM 和 BOM 對象,使用 Object.getOwnPropertyDescriptor()方法。支持這個方法的瀏覽器有 IE9+、 Firefox 4+、 Safari 5+、 Opera 12+和 Chrome。**