高程 第6章面向对象的程序设计 6.1 理解对象
面向?qū)ο?Object-Oriented,OO)的語言有一個標(biāo)志,那就是它們都有類的概念,而通過類可以創(chuàng)建任意多個具有相同屬性和方法的對象.
ECMAScript中沒有類的概念,因此它的對象也與基于類的語言中的對象有所不同.
ECMA-262把對象定義為:"無序?qū)傩缘募?其屬性可以包含基本值,對象或者函數(shù)".
嚴(yán)格來講,這就相當(dāng)于說對象是一組沒有特定順序的值.對象的每個屬性或方法都有一個名字,而每個名字都映射到一個值.正因為這樣,我們可以把EMCAScript的對象想象成散列表:無非就是一組名值對,其中值可以是數(shù)據(jù)或函數(shù).
每個對象老師基于一個引用類型創(chuàng)建的,這個引用類型可以是之前討論的原生類型,也可以是開發(fā)人員定義的類型.
6.1 理解對象
創(chuàng)建自定義對象的最簡單就是創(chuàng)建一個Object的實例,然后再為它添加屬性和方法.
var person=new Object();person.name="Nicholas";person.age=29;person.job="Software Engineer";person.sayName=function(){alert(this.name);};早期人員經(jīng)常使用這種創(chuàng)建一個名對象,并為它添加幾個屬性和方法.之后,對象字面量成為創(chuàng)建這種對象的首選模式.
var person={name:"Nicholas",age:29,job:"Software Engineer",sayName:function(){alert(this.name);}這個例子中的person對象與前面例子中的person對象一樣的,都有相同的屬性和方法.這些屬性在創(chuàng)建時都帶有一些特征值(characteristic),JavaScript通過這些特征值來定義它們的行為.
6.1.1屬性類型
ECMA-262第5版在定義只有內(nèi)部都用的特性(attribute)時,描述了屬性(property)的各種特征.ECMA-262定義這些特性是為了實現(xiàn)JavaScript引擎用的,因此在JavaScript中不能直接訪問它們.為了表示特征是內(nèi)部值,該規(guī)范把它們放在了兩對兒方括號中,例如[[Enumerable]].
ECMAScript中有兩種屬性:數(shù)據(jù)屬性和訪問器屬性.
1.數(shù)據(jù)屬性
數(shù)據(jù)屬性包含一個數(shù)據(jù)值的位置.在這個位置可以讀取和寫入值.數(shù)據(jù)屬性有4個描述其行為的特性.
[[Configurable]]:表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問器屬性.像前面例子中那樣直接在對象上定義的屬性,它們這個特性默認(rèn)值為true.
[[Enumerable]]:表示能否通過for-in循環(huán)返回屬性.像前面例子中那樣直接在對象上定義的屬性,它們的這個特性默認(rèn)值為true.
[[Writable]]:表示能否修改屬性的值.像前面例子中那樣直接在對象上定義的屬性,它們的這個特性默認(rèn)值為true.
[[Value]]:包含這個屬性的數(shù)據(jù)值.讀取屬性值的時候,從這個位置讀;寫入屬性值的時候,把新值保存在這個位置,這個特性的默認(rèn)值為undefined.
對于像前面的例子中那樣直接在對象上定義的屬性,它們的[[Configurable]],[[Enumberable]]和[[Writable]]特性都被設(shè)置為true,而[[Value]]特性被設(shè)置為指定的值.
var person={name:"Nicholas"};這里創(chuàng)建了一個名為name的屬性,為它指定 的值為"Nicholas".也就是說,[[Value]]特性將被設(shè)置為"Nicholas",而對這個值的任何修改都將反映在這個位置.
要修改屬性默認(rèn)的特性,必須使用ECMAScript 5的Object.defineProperty()方法.這個方法接收三個參數(shù):屬性所在的對象,屬性的名字和一個描述符對象.其中,描述符(descriptor)對象的屬性必須是:configurable,enumerable,writable和value.設(shè)置其中的一個或多個值,可以修改對應(yīng)的特性值.
var person={};Object.defineProperty(person,"name",{writable:false,value:"Nicholas"});alert(person.name);//Nicholasperson.name="Greg";alert(person.name);//Nicholas這個例子創(chuàng)建了一個名為name的屬性,它的值"Nicholas"是只讀的.這個屬性的值是不可修改的,如果嘗試為它指定新值,則在非嚴(yán)格模式下,賦值操作將被忽略;在嚴(yán)格模式下,賦值操作將會導(dǎo)致拋出錯誤.
類似的規(guī)則也適用于不可配置的屬性.
var person={};Object.defineProperty(person,"name",{configurable:false,value:"Nicholas"});alert(person.name);//Nicholasdelete person.name;alert(person.name);//Nicholas把configurable設(shè)置為false,表示不能從對象中刪除屬性.如果對這個屬性調(diào)用delete,則在非嚴(yán)格模式下什么也不會發(fā)生,而在嚴(yán)格模式下會導(dǎo)致錯誤.而且,一旦把屬性定義為不可配置的,就不能再把它變回可配置了.此時,再調(diào)用Object.defineProperty()方法修改除writable之外的特性,都會導(dǎo)致錯誤:
var person={};Object.defineProperty(person,"name",{configurable:false,value:"Nicholas"});Object.defineProperty(person,"name",{//Uncaught TypeError: Cannot redefine property: nameconfigurable:true,value:"Nicholas"});也就是說,可以多次調(diào)用Object.defineProperty()方法修改同一屬性,但把configurable特性設(shè)置為false之后就會有限制了.
在調(diào)用Object.defineProperty()方法時,如果不指定,configurable,enumerable和writable特性的默認(rèn)值都是false.
注意:IE8是第一個實現(xiàn)Object.defineProperty()方法的瀏覽器版本.然而,這個版本的實現(xiàn)存在諸多限制:只能在DOM對象上使用這個方法,而且只能創(chuàng)建訪問器屬性.由于實現(xiàn)不徹底,建議不要在IE8中使用Object.defineProperty()方法.
2.訪問器屬性
訪問器屬性不包含數(shù)據(jù)值:它們包含一對兒getter和setter函數(shù)(不過,這兩個函數(shù)都不是必需的).在讀取訪問器屬性時,會調(diào)用getter函數(shù),這個函數(shù)負(fù)責(zé)返回有效的值;在寫入訪問器屬性時,會調(diào)用setter函數(shù)并傳入新值,這個函數(shù)負(fù)責(zé)決定如何處理數(shù)據(jù).
訪問器屬性有如下4個特性:
[[Configurable]]:表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為數(shù)據(jù)屬性.對于直接在對象上定義的屬性,這個特性的默認(rèn)值為true.
[[Enumberable]]:表示能否通過for-in循環(huán)返回屬性.對于直接在對象上定義的屬性,這個特性的默認(rèn)值為true.
[[Get]]:在讀取屬性時調(diào)用的函數(shù).默認(rèn)值為undefined.
[[Set]]:在寫入屬性時調(diào)用的函數(shù).默認(rèn)值為undefined.
訪問器不能直接定義,必須使用Object.defineProperty()來定義.
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以上代碼創(chuàng)建了一個book對象,并給它定義兩個默認(rèn)的屬性:_year和edition.
_year前面的下劃線是一種常用的記號,用于表示只能通過對象方法訪問的屬性.而訪問器屬性year則包含一個getter函數(shù)和一個setter函數(shù).getter函數(shù)返回_year的值,setter函數(shù)通過計算來確定正確的版本.這是使用訪問器屬性的常見方式,即設(shè)置一個屬性的值會導(dǎo)致其他屬性發(fā)生變化.
不一定非要同時指定getter和setter.只指定getter意味著屬性是不能寫,嘗試寫入屬性會被忽略.在嚴(yán)格模式下,嘗試寫入只指定了getter函數(shù)的屬性會拋出錯誤.類似的,只指定 setter函數(shù)的屬性也不能讀,否則在非嚴(yán)格模式下會返回undefined,而在嚴(yán)格模式下會拋出錯誤.
在ECMAScript 5的這個方法之前,要創(chuàng)建訪問器屬性,一般都使用兩個非標(biāo)準(zhǔn)的方法:_defineGetter_()和_defineSetter_().
在不支持Object.defineProperty()方法的瀏覽器中不能修改[[Configurable]]和[[Enumberable]].
6.1.2 定義多個屬性
由于為對象定義多個屬性的可能性很大,ECMAScript 5又定義了一個Object.defineProperties()方法.利用這個方法可以通過描述符一次定義多個屬性.這個方法接收兩個對象參數(shù):第一個對象是要添加和修改其屬性的對象,第二個對象的屬性與第一個對象中要添加或修改的屬性一一對應(yīng).
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;}}} });以上代碼在book對象上定義了兩個數(shù)據(jù)屬性(_year和edition)和一個訪問器屬性(year).最終的對象與上一節(jié)定義的對象相同.唯一的區(qū)別是這里的屬性都是在同一時間創(chuàng)建的.
6.1,3 讀取屬性的特性
使用ECMAScript 5的Object.getOwnPropertyDescriptor()方法,可以取得給定屬性的描述符.這個方法接收兩個參數(shù):屬性所在的對象和要讀取其描述符的屬性名稱.返回值是一個對象,如果是訪問器屬性,這個對象的屬性有configurable,enumberable,get和set;如果是數(shù)據(jù)屬性,這個對象的屬性有configurable,enumberable,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);//2004alert(descriptor.configurable);//falsealert(typeof descriptor.get);//undefinedvar descriptor=Object.getOwnPropertyDescriptor(book,"year");alert(descriptor.value);//undefinedalert(descriptor.enumberable);//undefinedalert(typeof descriptor.get);//function對于數(shù)據(jù)屬性_year,value等于最初的值,configurable是false,而get等于undefined.對于訪問器屬性year,value等于undefined,enumerable是undefined,而get是一個指向getter函數(shù)的指針.
在JavaScript中,可以針對任何對象--包括DOM和BOM對象,使用Object.getOwnPropertyDescriptor()方法.
轉(zhuǎn)載于:https://www.cnblogs.com/sunshinegirl-7/p/4990261.html
總結(jié)
以上是生活随笔為你收集整理的高程 第6章面向对象的程序设计 6.1 理解对象的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在VisualState状态里更改Gri
- 下一篇: M2: XAML Controls(2)