JavaScript中,對象的屬性有兩種:數據屬性和訪問器屬性。javascript
數據屬性包括一個數據值的位置。在這個位置能夠讀取和寫入值。數據屬性有4個特性。java
[[configurable]]
:可配置。表示可否刪除屬性、可否修改屬性的特性、可否把屬性變爲訪問器屬性。[[enumerable]]
:可枚舉。表示可否經過for-in循環進行遍歷。[[writable]]
:可寫。表示可否修改屬性的值。[[value]]
:表示這個屬性的數據值。ES5提供了Object.defineProperty()
方法,來設置屬性的默認特性。該方法接收三個參數:屬性所在對象、屬性名字、屬性描述符對象。其中,描述符對象用來設置configurable、enumerable、writable、value中的一個或多個值。數組
ES5也提供了Object.defineProperties
方法,能夠定義多個屬性。函數
configurable: false
,就不能再變回configurable: true
了。不然,不管是否處於嚴格模式,都會拋出TypeError錯誤。foncigurable: false
,仍然能夠把writable的狀態由true改成false,可是沒法由false改成true。var person = {}; Object.defineProperty(person, 'name', { configurable: false, writable: false, value: 'Nicholas' }); // 測試:刪除屬性 delete person.name; // 因爲configurable: false,刪除失敗 console.log(person.name); // Nicholas // 測試:修改特性 Object.defineProperty(person, 'name', { configurable: true }); // 拋出錯誤:TypeError: Cannot redefine property: name // 測試:修改屬性的值 person.name = 'Greg'; // 因爲writable: false,修改失敗 console.log(person.name); // Nicholas
configurable: false
和writable: false
,就能夠建立一個真正的常量屬性。Object.seal()
方法,會在一個現有對象上調用Object.preventExtensions()
,並把全部屬性標記爲configurable: false
。Object.freeze()
方法,會在一個現有對象上調用Object.seal()
,並把全部屬性標記爲writable: false
。ES5提供了Object.getOwnPropertyDescriptor()
方法,來取得給定屬性的描述符。該方法接收兩個參數:屬性所在對象、屬性名字。返回值是一個對象,其屬性有configurable、enumerable、writable、value。測試
還有一種區分枚舉屬性enumerable的方法是propertyIsEnumerable()
。該方法不檢查原型鏈。this
// 使用Object.definedProperty設置的屬性 var descriptor = Object.getOwnPropertyDescriptor(person, 'name'); console.log(descriptor.configurable); // false console.log(descriptor.enumerable); // false console.log(descriptor.writable); // false console.log(descriptor.value); // Nicholas // 直接定義在對象上的屬性 var person2 = { name: "Greg" }; var descriptor2 = Object.getOwnPropertyDescriptor(person2, 'name'); console.log(descriptor2.configurable); // true console.log(descriptor2.enumerable); // true console.log(descriptor2.writable); // true console.log(descriptor2.value); // Greg // propertyIsEnumerable()方法 console.log(person.propertyIsEnumerable('name')); // false console.log(person2.propertyIsEnumerable('name')); // true
Object.keys(obj)
會返回一個數組,包含全部可枚舉屬性。不檢查原型鏈。Object.getOwnPropertyNames(obj)
會返回一個數組,包含全部屬性,不管是否枚舉。不檢查原型鏈。prop in obj
會返回一個布爾值,判斷對象的屬性是否存在,不管是否枚舉。檢查原型鏈。obj.hasOwnProperty(prop)
會返回一個布爾值,判斷對象的指定屬性是否存在,不管是否枚舉。不會檢查原型鏈。for-in
循環的遍歷中。var myObject = {}; Object.defineProperty(myObject, 'a', { enumerable: true, value: 2 }); Object.defineProperty(myObject, 'b', { enumerable: false, value: 3 }); // propertyIsEnumerable console.log(myObject.propertyIsEnumerable('a')); // true console.log(myObject.propertyIsEnumerable('b')); // false // Object.keys() console.log(Object.keys(myObject)); // ["a"] // Object.getOwnPropertyNames() Object.getOwnPropertyNames(myObject); // ["a", "b"] // in操做符 console.log('a' in myObject); // true console.log('b' in myObject); // true console.log('toString' in myObject); // true // hasOwnProperty() console.log(myObject.hasOwnProperty('a')); // true console.log(myObject.hasOwnProperty('b')); // true console.log(myObject.hasOwnProperty('toString')); // false // 遍歷 for (var k in myObject) { console.log( k, myObject[k] ); } // a 2
訪問器屬性有4個特性。對於訪問器屬性,JavaScript會忽略它們的writable和value特性,取而代之的該關心get和set屬性。設計
[[configurable]]
:表示可否刪除屬性、可否修改屬性的特性、可否把屬性變爲訪問器屬性。[[enumerable]]
:表示可否經過for-in循環進行遍歷。直接定義在對象上的屬性,默認值爲true。[[get]]
:讀取屬性時調用的函數。直接定義在對象上的屬性,默認值爲undefined。[[set]]
:寫入屬性時調用的函數。直接定義在對象上的屬性,默認值爲undefined。一樣使用Object.defineProperty()
方法和Object.defineProperties
方法設置訪問其屬性。code
var book = { _year: 2004, edition: 1 }; Object.defineProperty(book, 'year', { get: function() { return this._year; }, set: function(newYear) { if (newYear > 2004) { this._year = newYear; this.edition += (newYear - 2004); } } }); // 測試 book.year = 2005; // 注意:defineProperty中定義的屬性名爲year,而非_year console.log(book.edition); // 2
另外一種設置getter和setter函數的方法以下:對象
var myObject = { // 定義getter get foo() { return 'You get: ' + this._foo_; }, // 定義setter set foo(val) { this._foo_ = val; } } // 測試 myObject.foo = 2; console.log(myObject.foo); // You get: 2
一樣使用Object.getOwnPropertyDescriptor()
方法取得給定屬性的描述符。ip
// 使用Object.definedProperty設置的屬性 var descriptor = Object.getOwnPropertyDescriptor(book, 'year'); console.log(descriptor.configurable); // false console.log(descriptor.enumerable); // false console.log(typeof descriptor.get); // function console.log(typeof descriptor.set); // function // 直接定義在對象上的屬性 var descriptor = Object.getOwnPropertyDescriptor(myObject, 'foo'); console.log(descriptor.configurable); // true console.log(descriptor.enumerable); // true console.log(typeof descriptor.get); // function console.log(typeof descriptor.set); // function
參考:《JavaScript高級程序設計》、《你不知道的JavaScript(上卷)》