js中屬性類型:數據屬性與訪問器屬性
js中屬性類型分為兩種:數據屬性和訪問器屬性
在js中,對象都是由名值對構成的,名:就是我們所說的屬性名,值就是屬性對應的值(基本值、對象、方法)。
ECMA-262第5版定義了只有內部才用的特性,描述了屬性的各種特征,比如,這個屬性能否被刪除、能否被枚舉、能否被修改、以及讀取屬性的值。
這些特性是為了實現JavaScript引擎用的,因此在JavaScript中不能直接訪問他們。
1、先來說一下數據屬性
數據屬性:包含一個數據值的位置。在這個位置可以讀取和寫入值。數據屬性有4個描述其行為的特性。
Configurable:表示能否通過delete刪除屬性,從而重新定義屬性,能否修改屬性的特性,或則能否把屬性修改為訪問器屬性
Enumberable:表示能否通過for-in循環返回屬性(枚舉),自定義的對象屬性,默認值為true。
Writable:表示能否修改屬性的值,自定義對象的屬性,這個特性值默認為true。
Value:包含這個屬性的數據值,讀取屬性值的時候從這個讀,寫入屬性值的時候,把新值保存在這個位置。這個特性的默認值為undefined。
ECMAScript5定義了一個修改屬性的這些默認特性的方法:Object.defineProperty();
這個方法接收三個參數:屬性所在的對象、屬性的名字(字符串形式)、一個描述符對象。其中描述符對象的屬性必須是:configurable、enumberable、writable、value,設置其中的一個或多個值,可以修改對應的特性值。例如:
var person={}; Object.defineProperty(person,"name",{ writable:false, value:"Nicholas" }); console.log(Object.getOwnPropertyDescriptor(person,"name"));//讀取屬性的特性的方法,後面會介紹 console.log(person.name);//Nicholas person.name="Greg"; console.log(person.name);//Nicholas
上面,對name屬性的兩個特性writable、value進行了設置,可見,我們更改name屬性的值是無效的,在嚴格模式下會報錯;
當用Object.defineProperty()創建一個新屬性時,若不指定configurable、enumberable、writable這些特性時,都是false,若果在原來設置過的基礎上設置其中的一個或多個,則無此限制。
另外,當設置configurable為false後,也就是把該屬性變成不可設置的,除delete不能刪除該屬性外,再次用Object.defineProperty()方法設置除writable特性外的其它特性時,在非嚴格模式時什麽都不會發生,在嚴格模式時會報錯。(同時configurable特性也設置不了true了!!!);
2、訪問器屬性:
訪問器屬性不包含數據值,他們包含一對兒getter和setter函數(不過,這兩個函數都不是必須的)。在讀取訪問器屬性時,會調用getter函數,這個函數負責返回有效的值;在寫入訪問器屬性時,會調用setter函數並傳入新值,這個函數負責決定如何處理數據。訪問器屬性有如下4個特性。
configurable:表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或則能否把屬性修改為數據屬性。對於直接在對象上定義的屬性,這個特性的默認值為true。
enumberable:表示能否通過for-in來循環返回屬性。對於直接在對象上定義的屬性,這個特性的默認值為true。
get:讀取屬性時調用的函數。默認值為undefined
set:在寫入屬性時調用的函數。默認值為undefined
訪問器屬性不能直接定義,必須使用Object.defineProperty()來定義。請看下面的例子:
var book={
_year:2004,
edition:1
};
//下邊給book對象設置一個year(訪問器屬性)
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;
console.log(book.edition);//1
console.log(book._year);//2005
console.log(book.year);//2005
console.log(book);//{_year: 2005, edition: 1}
可見,創建的訪問器屬性,用console是打印不出來的,我們常見的使用訪問器屬性的方式就是上述這種方式,修改訪問器屬性,會導致其他屬性變化!!!
當然,不一定非要指定get和set,只指定get就是只能讀,不能寫,只指定set就是不能讀。
當然也可以同時定義多個屬性,用:Object.defineProperties()方法,利用這個方法可以通過描述符一次定義多個屬性,這個方法接收兩個參數,第一個參數是要添加和修改其屬性的對象,第二個參數(對象:描述符)的屬性與第一個對象中要添加或修改的屬性要一一對應。如:
var book={};
Object.defineProperties(book,{
_year:{//定義一個數據屬性,其它為指定的特性值為false
writable:true,
value:2004
},
edition:{//同樣是一個數據屬性
writable:true,
value:1
},
year:{
get:function(){
return this._year;
},
set:function(newValue){
if(newValue>2004){
this._year=newValue;
this.edition+=newValue-2004;
}
}
}
});
book.year=2003;
console.log(book);//{_year: 2004, edition: 1}
book.year=2005;
console.log(book);//{_year: 2005, edition: 1}
// Object.getOwnPropertyDescriptor();用來讀取給定屬性的描述符,這個方法有兩個參數,屬性所在的對象和要讀取其描述符的屬性名,返回一個對象。
var descriptor=Object.getOwnPropertyDescriptor(book,"_year");//數據屬性
var descriptor2=Object.getOwnPropertyDescriptor(book,"year");//訪問器屬性
console.log(descriptor);//{value: 2005, writable: true, enumerable: false, configurable: false}
console.log(descriptor2);//{get: ?, set: ?, enumerable: false, configurable: false}
Object.getOwnPropertyDescriptor();用來讀取給定屬性的描述符,這個方法有兩個參數,屬性所在的對象和要讀取其描述符的屬性名,返回一個對象。這個方法可以在任何瀏覽器使用。
js中屬性類型:數據屬性與訪問器屬性