JavaScript中屬性和特性是完全不同的兩個(gè)概念,這里我將根據(jù)自己所學(xué),來深入理解JavaScript中的屬性和特性。
主要內(nèi)容如下:
第一部分:理解JavaScript中對(duì)象的本質(zhì)、對(duì)象與類的關(guān)系、對(duì)象與引用類型的關(guān)系
對(duì)象的本質(zhì):ECMA-262把對(duì)象定義為:無序?qū)傩缘募希鋵傩钥梢园局怠?duì)象或者函數(shù)。即對(duì)象是一組沒有特定順序的值,對(duì)象的每個(gè)屬性或方法都有一個(gè)名字,而這個(gè)名字都映射到一個(gè)值。故對(duì)象的本質(zhì)是一個(gè)散列表:其中是一組名值對(duì),值可以是數(shù)據(jù)或函數(shù)。
對(duì)象和類的關(guān)系:在JavaScript中,對(duì)象和類沒有任何關(guān)系。這是因?yàn)镋CMAScript中根本就沒有類的概念,它的對(duì)象與其他基于類的語言中的對(duì)象是不同的。
對(duì)象和引用類型的關(guān)系:對(duì)象和引用類型并不是等價(jià)的,因?yàn)槊總€(gè)對(duì)象都是基于一個(gè)引用類型創(chuàng)建的。
第二部分:對(duì)象屬性如何進(jìn)行分類
由構(gòu)造函數(shù)或?qū)ο笞置媪糠椒▌?chuàng)建的對(duì)象中具有屬性和方法(只要提到屬性和方法,它們一定是屬于對(duì)象的;只要提到對(duì)象,它一定是具有屬性和方法的(自定義除外)),其中屬性又可分為數(shù)據(jù)屬性和訪問器屬性,他們的區(qū)別如下:
數(shù)據(jù)屬性一般用于存儲(chǔ)數(shù)據(jù)數(shù)值,訪問器屬性不包含數(shù)據(jù)值
訪問器屬性多用于get/set操作
第三部分:屬性中特性的理解
ECMAScript為了描述對(duì)象屬性(property)的各種特征,定義了特性(attribute)這個(gè)概念。也就是說特性不同于屬性,特性是為了描述屬性的。下面,我將分別講解:
1.數(shù)據(jù)屬性及其特性
剛剛我們說過,數(shù)據(jù)屬性是用于存儲(chǔ)數(shù)據(jù)數(shù)值的,因此數(shù)據(jù)屬性具有一個(gè)數(shù)據(jù)值的位置,在這個(gè)位置可以讀取和寫入值。數(shù)據(jù)屬性有4個(gè)描述其行為的特性,由于ECMAScript規(guī)定:在JavaScript中不能直接訪問屬性的特性(注意:不是不能訪問),所以我們把它放在兩組方括號(hào)中。如下:
這些特性都具有默認(rèn)值,但是如果這些默認(rèn)值不是我們想要的,該怎么辦呢?當(dāng)然就是修改啦!我們可以通過Object.defineProperty()方法來修改屬性默認(rèn)的特性。英文difineProperty即為定義屬性的意思。這個(gè)方法接收三個(gè)參數(shù):屬性所在的對(duì)象、屬性的名字和一個(gè)描述符對(duì)象。其中第三個(gè)參數(shù)描述符對(duì)象是對(duì)象字面量的方法創(chuàng)建的,里面的屬性和屬性值實(shí)際上保存的是要修改的特性和特性值。
下面通過幾個(gè)例子來深入理解。
a
var person={};Object.defineProperty(person,"name",{ writable:false, value:"zhuzhenwei"});console.log(person.name);//zhuzhenweiperson.name="heting";console.log(person.name);//zhuzhenwei 這里我用對(duì)象字面量的方法創(chuàng)建了一個(gè)對(duì)象,但是沒有同時(shí)創(chuàng)建方法和屬性。而是利用了Object.defineProperty()方法來創(chuàng)建了屬性和修改了默認(rèn)值。這里將writable設(shè)置為false,于是后面我試圖修改person.name時(shí),是無效的。
b
var person={};Object.defineProperty(person,"name",{ value:"zhuzhenwei"});console.log(person.name);//zhuzhenweiperson.name="heting";console.log(person.name);//zhuzhenwei注意看這個(gè)例子,這個(gè)例子中我刪去了writable:false,為什么還是不能修改呢?這是因?yàn)橹拔以诮榻B特性時(shí),前三個(gè)默認(rèn)為ture,是在創(chuàng)建對(duì)象并創(chuàng)建屬性的情況下得到的。對(duì)于通過調(diào)用Object.defineProperty()方法創(chuàng)建的屬性,其前三個(gè)特性的默認(rèn)值均為false,這里需要注意。
c
var person={};Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:false});console.log(person.name);//zhuzhenweidelete person.name;console.log(person.name);//zhuzhenwei 這里我們將新建的屬性name的特性設(shè)置為了configurable:false;因此下面刪除屬性的操作是無效的。根據(jù)b,可知configurable,默認(rèn)就是false,即使去掉也不可修改。
d
var person={};Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:true});console.log(person.name);//zhuzhenweidelete person.name;console.log(person.name);//undefined 在這里我將默認(rèn)的configurable的值由默認(rèn)的false修改為了true,于是變成了可配置的,那么最后就成功刪除了。
e
var person={};Object.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:false});console.log(person.name);//zhuzhenweiObject.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:true});console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…)如果之前已經(jīng)設(shè)置成為了false,那么后面再改成true也是徒勞的,即:一旦把屬性設(shè)置成為不可配置的,就不能再把它變回可配置了。
f
console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…)var person={};Object.defineProperty(person,"name",{ value:"zhuzhenwei",});console.log(person.name);//zhuzhenweiObject.defineProperty(person,"name",{ value:"zhuzhenwei", configurable:true});console.log(person.name);//Uncaught TypeError: Cannot redefine property: name(…)這里可以說明,即使前一步我們不管默認(rèn)的configurable:false,后面得到的仍是不可配置。于是,可以得出結(jié)論,為了可配置,必須在第一次調(diào)用Object.defineProperty()函數(shù)時(shí)就將默認(rèn)的值修改為true。
2.訪問器屬性及其特性
之前提到,訪問器屬性不包含數(shù)據(jù)值,他們包含一對(duì)getter函數(shù)和setter函數(shù)(這兩個(gè)函數(shù)不是必須的)。在讀取訪問器屬性時(shí),會(huì)調(diào)用getter函數(shù),這個(gè)函數(shù)負(fù)責(zé)返回有效的值;在寫入訪問器屬性是,會(huì)調(diào)用setter函數(shù)并傳入新值,這個(gè)函數(shù)負(fù)責(zé)決定如何處理數(shù)據(jù)。同樣,由于不能通過JavaScript來直接訪問得到訪問器屬性的特性,所以下面列出的特性將由[[]]括起來以作區(qū)分。
注意:1.相對(duì)于數(shù)據(jù)屬性,我們發(fā)現(xiàn)訪問器屬性中沒有writable特性和value特性。這是因?yàn)樵L問器屬性不包含數(shù)據(jù)值,那么我們?cè)趺串?dāng)然就不可修改屬性的值(用不到writable特性),更不用考慮value了。
2.訪問器屬性不能直接定義,必須是用Object.defineProperty()來定義。(通過這個(gè)規(guī)定我們就能準(zhǔn)確地判斷出訪問器屬性和數(shù)據(jù)屬性了)
通過下面這個(gè)例子來深入理解:
var book={ _year:2004, edition:1};Object.defineProperty(book,"year",{ get:function(){<br> return this._year; }, set:function(newValue){ if(newValue>2004){ this._year=newValue; this.edition+=newValue-2004; } }});book.year=2005;console.log(book.edition);//2幾個(gè)需要深入理解的地方:
3.如何利用Object.defineProperties()方法定義多個(gè)特性
顯然,一個(gè)對(duì)象不可能只具有一個(gè)屬性,因此,定義多個(gè)屬性的可能性很大,于是JavaScript提供了Object.defineProperties()方法解決這個(gè)問題。這個(gè)方法接收兩個(gè)參數(shù),第一個(gè)是要定義屬性所在的對(duì)象,第二個(gè)是一個(gè)對(duì)象字面量方法創(chuàng)建的對(duì)象,對(duì)象的屬性名即為要定義的特姓名,對(duì)象的屬性值又是一個(gè)對(duì)象,這個(gè)對(duì)象里的屬性名和屬性值分別是特性名和特性值(這里不是很好理解,看例子即可)。
var book={};Object.defineProperties(book,{ _year:{ writable:true, value:2004 }, edition:{ writable:true, value:1 }, year:{ get:function(){ return this._year; }, set:function(){ if(newValue>2004){ this._year=newValue; this.edition+=newValue-2004; } } }}); 4.如何利用Object.getOwnPropertyDescripter()方法讀取屬性的描述符以讀取屬性的特性
我們可以使用Object.getOwnPropertyDescripter()方法來取得給定屬性的描述符。getOwnPropertyDescripter即為取得自身屬性描述符的意思。這個(gè)方法接收兩個(gè)參數(shù):屬性所在的對(duì)象要要讀取其描述符的屬性名稱。返回一個(gè)對(duì)象。
對(duì)于訪問器屬性而言,這個(gè)對(duì)象的屬性有configurable、enumerable、get和set;
對(duì)于數(shù)據(jù)屬性而言,這個(gè)對(duì)象的屬性有configurable、enumerable、writable和value。
var book={};Object.defineProperties(book,{ _year:{ value:2004 }, edition:{ value:1 }, year:{ get:function(){ return this._year; }, set:function(){ if(newValue>2004){ this._year=newValue; this.edition+=newValue-2004; } } }});var descriptor=Object.getOwnPropertyDescriptor(book,"_year");console.log(descriptor.value);//2004console.log(descriptor.configurable);//false 因?yàn)橥ㄟ^Object.defineProperties()方法創(chuàng)建的屬性的特性configurable enumerable都是falseconsole.log(typeof descriptor.get);//undefined 注意:這是數(shù)據(jù)屬性,是不具有g(shù)et特性的var descriptor=Object.getOwnPropertyDescriptor(book,"year");console.log(descriptor.value);//undefinedconsole.log(descriptor.enumerable);//falseconsole.log(typeof descriptor.get);//function get雖然是屬性的一個(gè)特性,但是它也是函數(shù)。以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,同時(shí)也希望多多支持武林網(wǎng)!
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注