對象屬性

屬性的類型

ECMA-262 第 5 版在定義只有內部才用的特性(attribute)時,描述了屬性(property)的各類特徵。定義這些屬性是爲了實現JavaScript引擎用的,所以在JavaScript中不能直接訪問它們。爲了我表示特性是內部值,改規範把它們放在了兩對兒方括號中,例如[[Enumerable]]。瀏覽器

ECMAScript 中有兩種屬性:數據屬性和訪問器屬性函數

1.數據屬性

數據屬性包含一個數據值的位置。在這個位置能夠讀取和寫入值。數據屬性有 4 個描述其行爲的特性。this

  • [[Configurable]]:表示可否經過 delete 刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成訪問器屬性。直接在對象上定義的屬性,它們的這個特性默認值爲 true。
  • [[Enumerable]]:表示可否經過 for-in 循環返回屬性。直接在對象上義的屬性,它們的這個特性默認值爲 true。
  • [[Writable]]:表示可否修改屬性的值。直接在對象上定義的屬性,它們的這個特性默認值爲 true。
  • [[Value]]:包含這個屬性的數據值。讀取屬性值的時候,從這個位置讀;寫入屬性值的時候,新值保存在這個位置。這個特性的默認值爲 undefined。

Object.defineProperty()

做用:修改屬性默認的特性
參數:屬性所在的對象、屬性的名字、和一個描述符對象。描述符對象的屬性必須是configurable、enumerable、writable 和 value。code

Object.defineProperty(person, "name", { 
     writable: false, 
     value: "Nicholas" 
}); 
alert(person.name); //"Nicholas" 
person.name = "Greg"; 
alert(person.name); //"Nicholas"

一旦把configurable屬性定義爲不可配置的,就不能再把它變回可配置了。此時,再調用 Object.defineProperty()方法修改除 writable 以外
的特性,都會致使錯誤htm

var person = {}; 
Object.defineProperty(person, "name", { 
    configurable: false, 
    value: "Nicholas" 
}); 
//拋出錯誤
Object.defineProperty(person, "name", { 
    configurable: true, 
    value: "Nicholas" 
});

在調用 Object.defineProperty()方法時,若是不指定,configurable、enumerable 和writable 特性的默認值都是 false(未調用改方法時默認值都爲true)對象

2. 訪問器屬性

訪問器屬性不含數據值;他們包含一對兒getter和setter函數(不是必需的)。在讀取訪問器屬性時,會調用getter函數,這個函數負責返回有效的值;在寫入訪問器屬性時,會調用setter函數並傳入新值。這個函數負責如何處理數據ip

訪問器的四個屬性:get

  • [[Configurable]]:表示可否經過 delete 刪除屬性從而從新定義屬性,可否修改屬性的特性,或者可否把屬性修改成數據屬性。對於直接在對象上定義的屬性,這個特性的默認值爲true。
  • [[Enumerable]]:表示可否經過 for-in 循環返回屬性。對於直接在對象上定義的屬性,這個特性的默認值爲 true。
  • [[Get]]:在讀取屬性時調用的函數。默認值爲 undefined。
  • [[Set]]:在寫入屬性時調用的函數。默認值爲 undefined。

訪問器屬性不能直接定義,必須使用 Object.defineProperty()來定義。it

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

支持 ECMAScript 5 的這個方法的瀏覽器有 IE9+(IE8 只是部分實現)、Firefox 4+、Safari 5+、Opera 12+ 和 Chrome 。在這個方法以前,要建立訪問器屬性,通常都使用兩個非標準的方法:__defineGetter__()和__defineSetter__()。這兩個方法最初是由 Firefox 引入的,後來 Safari 三、Chrome 1 和 Opera 9.5 也給出了相同的實現io

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 
AccessorPropertiesExample02.htm 
在不支持 Object.defineProperty() 方法的瀏覽器中不能修改 [[Configurable]] 和 [[Enumerable]]。

2 定義多個屬性

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; 
            } 
        } 
    } 
});

3 讀取屬性的特性

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