對象是一個屬性集合,對象的基本特徵是屬性名(name)和屬性值(value)。ES5 增長了屬性描述符,能夠更細膩的控制屬性的不一樣操做。屬性描述符有 configurable、writable 和 enumerable。javascript
屬性描述符一般和 Object.defineProperty/Object.defineProperties 一塊兒使用來定義屬性,它也會受到諸如 Object.freeze/Object.seal 等方法改變。java
1. configurable 當且僅當 configurable 爲 true 時,該屬性纔可以被改變,也可以被刪除(delete),默認爲 false函數
var obj = {} Object.defineProperty(obj, 'name', { value: 'John' }) // 不能 delete delete obj.name // false Object.defineProperty(obj, 'name', { configurable: true, value: 'John' }) // 能夠delete delete obj.name // true
2. writable 當且僅當 writable 爲 true 時,該屬性才能被賦值運算符(=)改變,默認爲 falsethis
var obj = {} Object.defineProperty(obj, 'name', { value: 'John' }) obj.name = 'Backus' // 修改不起做用,仍然是 John,嚴格模式中會報錯阻止修改 Object.defineProperty(obj, 'name', { writable: true, value: 'John' }) obj.name = 'Backus' // 被改成了 backus
3. enumerable 當且僅當 enumerable 爲 true 時,該屬性纔可以出如今對象的枚舉屬性(for in)中,默認爲 false對象
var obj = {} Object.defineProperty(obj, 'name', { value: 'John' }) // 不能遍歷 for (var a in obj) { console.log(a) // 無輸出 } Object.defineProperty(obj, 'name', { enumerable: true, value: 'John' }) // 能夠遍歷 for (var a in obj) { console.log(a) // 輸出 "name" }
ES6 的 Object.keys 只返回 enumerable=true 的屬性blog
var obj = {name: 'John'} Object.defineProperty(obj, 'name', { value: 'Backus', enumerable: true }) Object.defineProperty(obj, 'age', { value: 30, enumerable: false }) Object.keys(obj) // ['name']
能夠經過 propertyIsEnumerable 方法判斷屬性的 enumerable 值ip
obj.propertyIsEnumerable('name') // true obj.propertyIsEnumerable('age') // false
4. 使用 ES3(傳統的) JSON 方式定義對象,其 configurable/writable/enumerable 默認都是 true,以下get
var obj = {name: 'John', age: 30} // configurable delete obj.name // true // writable obj.age = 32 // true // enumerable for (var a in obj) { console.log(a) // age }
也即it
var obj = {name: 'John', age: 30}
等同於io
Object.defineProperty(obj, 'name', { value: 'John', configurable: true, writable: true, enumerable: true }) Object.defineProperty(obj, 'age', { value: 33, configurable: true, writable: true, enumerable: true })
5. 使用 ES5 的 Object.defineProperty/Object.defineProperties 方式定義對象,其 configurable/writable/enumerable 默認都是 false,以下
var obj = {} Object.defineProperty(obj, 'name', { value: 'John' }) Object.defineProperty(obj, 'age', { value: 33 }) // configurable delete obj.name // false // writable obj.age = 32 // false // enumerable for (var a in obj) { console.log(a) // 無輸出,不能遍歷 }
也即
Object.defineProperty(obj, 'name', { value: 'John' })
等同於
Object.defineProperty(obj, 'name', { value: 'John', configurable: false, writable: false, enumerable: false })
數據屬性描述符彙總以下
存取描述符是由一對 getter-setter 函數功能來描述的屬性,格式爲
name: { get: function() { ... }, set: function(newVal) { ... }, enumerable: true, configurable: true }
例如
var obj = {} Object.defineProperty(obj, 'name', { configurable: true, enumerable: true, get: function() { console.log('get') return this.value }, set: function(newVal) { console.log('set') this.value = newVal } }) // 賦值會調用 set 方法 obj.name = 'John' // 取值會調用 get 方法 obj.name
與上述的屬性描述符只能存在一種,即二選一,不能同時存在,不然會報錯
var obj = {} // 錯誤方式一 Object.defineProperty(obj, 'name', { value: 'John', get: function() { console.log('get') return this.value } }) // 錯誤方式二 Object.defineProperty(obj, 'name', { writable: true, get: function() { console.log('get') return this.value } })
Firefox 報錯以下
存取描述符彙總以下
Object.defineProperty 上面已經介紹過,Object.defineProperties 批量定製對象屬性,內部其實循環方式調用 Object.defineProperty
Object.defineProperties(obj, { name: { value: 'John', writable: true }, age: { value: 30, enmuerable: true } })
Object.getOwnPropertyDescriptor 返回該對象某屬性的描述器,描述器自身是一個對象
var obj = {} Object.defineProperty(obj, 'name', { value: 'Backus', writable: true, enumerable: true }) var des = Object.getOwnPropertyDescriptor(obj, 'name') console.log(des)
輸出如圖