1. 程式人生 > >ECMAScript資料屬性和訪問器屬性

ECMAScript資料屬性和訪問器屬性

ECMA-262中把物件定義為:“無序屬性的集合,其屬性可以包含基本值、物件或者函式。”
js中每個物件都是基於一個引用型別建立的。
建立自定義物件的最簡單方式無非是建立一個object的例項,再為其新增屬性和方法。
效果圖
用物件字面量模式可以寫成這樣:
效果圖
以上兩種寫法建立的person物件具有相同的屬性和方法,這些屬性在建立時都帶有一些特徵值,javascript通過這些特徵值來定義他們的行為。

ECMA-262第五版定義了一些特性來描述屬性的各種特徵,這些特性是為了實現javascript引擎用的,屬於內部值,因此不能直接訪問他們。

ECMAScript中有兩種屬性:資料屬性和訪問器屬性。

資料屬性:資料屬性包含一個數據值的位置,在該位置可以讀取和寫入值。資料屬性有4個描述其行為的特性。
[[Configurable]] : 表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問器屬性;
[[Enumerable]] : 表示能否通過for-in迴圈返回屬性;
[[Writable]] : 表示能否修改屬性的值;
[[Value]] : 包含這個屬性的資料值,讀取屬性值的時候,從這個位置讀,寫入屬性值的時候,把新值儲存在這個位置。預設值為undefined。
對於上面建立的物件裡定義的屬性,它們的[[Configurable]]、[[Enumerable]]、[[Writable]]特性都被設定為true,而[[Value]]特性被設定為指定的值。
要修改預設的特性,必須使用ECMAScript5的Object.defineProperty()方法,該方法接收三個引數:屬性所在物件、屬性的名字和一個描述符物件,其中描述符物件的屬性必須是:configurable、enumerable、writable、value。設定其中一個或多個,可修改對應的特性值。例如:
效果圖


該例子建立了一個name的屬性,設定其值“zuoran”是隻讀的。這個屬性的值是不可修改的,如果嘗試為其指定新值,在非嚴格模式下,賦值操作會被忽略,在嚴格模式下會丟擲錯誤。
下面設定configurable(不可配置屬性)的值:
效果圖
這裡把configurable設定為false,表示不能從物件中刪除屬性,如果對該屬性呼叫delete,在非嚴格模式下什麼也不會發生,在嚴格模式下會丟擲錯誤,而且,一旦把屬性的configurable設定為false,就不可能在設定為true,因為此時再呼叫Object.defineProperty()方法修改除writable之外的特性,都會導致錯誤。
總結說可以多次呼叫Object.defineProperty()方法修改同一個屬性,但是在把configurable特性設定為false之後就會有限制了。在呼叫Object.defineProperty()方法時,如果不指定,configurable、enumerable和writable特性的預設值都是false。

訪問器屬性:該屬性不包含資料值,包含一對getter和setter函式。訪問器屬性有如下4個特性:
[[Configurable]] : 表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬性修改為訪問器屬性;
[[Enumerable]] : 表示能否通過for-in迴圈返回屬性;
[[Get]] : 在讀取屬性時呼叫的函式,預設值是undefined;
[[Set]] : 再寫入屬性時呼叫的函式,預設值是undefined。
要定義訪問器屬性必須使用Object.defineProperty()方法,例如:
效果圖
這是使用訪問器屬性的常用方式,即設定一個屬性的值導致其他屬性發生變化。不一定非要同時指定兩個屬性,只指定getter意味著屬性不能寫,只指定setter意味著屬性不能讀。如下:
效果圖
在非嚴格模式下不會發生什麼,在嚴格模式下會丟擲錯誤:
效果圖
效果圖

ECMAScript5還定義了一個Object.defineProperties()方法,用於定義多個屬性,該方法接收兩個物件引數,如下呼叫:
效果圖

ECMAScript5的Object.getOwnPropertyDescriptor()方法可以讀取屬性的特性。該方法接收兩個引數:屬性所在物件和要讀取其描述符的屬性名稱,返回值是一個物件,若是資料屬性,即為之前資料屬性對應的4個特性,若是訪問器屬性,即為之前訪問器屬性對應的4個特性。例如(對應上面定義的多個屬性):
效果圖

以上參考《JavaScript高階程式設計(第3版)》。