昨天談到了這些問題,發現認識比較片面。決定仔細看看並總結一下。
研究Object的部分ES5 API。可能會提到部分ES6內容。es6
即描述對象屬性特性的描述符數組
value
值this
writable
只讀性spa
enumerable
可枚舉性prototype
configurable
可配置性(屬性的刪除與從新配置)指針
value
默認爲undefined
在使用Object.create()
和Object.defineProperty
時writable
、enumerable
、configurable
默認均爲false
code
get
不可與value
同時使用,會由屬性的讀取觸發。對象
set
不可與writable
同時使用,會由屬性的寫入觸發。繼承
將會在其餘的api中介紹屬性描述符的用法
Object.create(proto, [ propertiesObject ])
此api的做用是以proto
爲原型,以propertiesObject
中自有屬性(不包含propertiesObject
的原型上的屬性,包含全部不可枚舉屬性)爲屬性建立一個新的對象。
// 非嚴格模式下運行,嚴格模式下會拋出異常 const proto = { saySize () { console.log(this.size) } } const propertiesObject = { size: { enumerable: false, configurable: false, value: 'large' }, color: { writable: true, enumerable: true, configurable: true, value: 'red' } } let newObj = Object.create(proto, propertiesObject) // 原型 newObj.saySize() // "large" // writable newObj.size = 'small' newObj.color = 'green' console.log(newObj.size, newObj.color) // "large,green" // enumerbale for(key in newObj){ console.log(key) } // "color" // "saySize" delete newObj.size // false delete newObj.color // true
上述代碼中的proto
使用Fun.prototype
便可實現原型鏈的繼承。
那麼要怎樣才能枚舉出enumerable:false
的屬性呢?
Object.defineProperty(obj, prop, descriptor)
此api容許修改或向obj
添加屬性 obj
爲目標對象,prop
爲要修改或添加的屬性,descriptor
爲屬性描述符
let tempObj1 = {} Object.defineProperty(tempObj, 'name', { value: 'temp', writable: false, enumerable: true, configurable: false }) console.log(tempObj) // Object {name: "temp"} // 拋出異常 Object.defineProperty(tempObj, 'name', { value: temp, writable: true })
對於configurable: false
的屬性禁止修改屬性描述符,會拋出異常。
let tempObj2 = {_name: 'temp2'} Object.defineProperty(tempObj2, 'name', { get () { return `名字爲${this._name}` }, set (value) { console.log(`新名字爲${value}`) } }) console.log(tempObj2.name) // "名字爲temp2" tempObj2.name = 'temp2.0' // "新名字爲temp2.0"
能夠觀察到 讀屬性值與 寫屬性值分別觸發了get
和set
屬性訪問器。
代碼中所用到的"`名字爲${this._name}`" 爲es6模板字符串,實現拼串
Object.defineProperties(obj, props)
此api方便了屬性的批量修改,第二個參數與Object.create()
的第二個參數結構相同。
let tempObj3 = {name:'temp'} Object.defineProperties(tempObj3, { name: { value: 'newTemp', writable: true }, color: { value: 'red', writable: true, enumerable: true } }) console.log(tempObj3) // Object {name: "newTemp", color: "red"}
咱們也看到了對於enumerable:false
的屬性是不可枚舉的。甚至ES6中還有「隱蔽性」更高的Symbol()
能夠做爲屬性鍵。那麼怎麼才能正確的檢測與獲取對象的屬性呢?
咱們先建立一個對象用於實驗後續的全部方法。
原型和自身都各包含三種屬性:enumerable: false
,enumerable: true
,Symbol()
const proto = Object.create(null, { supTrue: { value: 'value1', enumerable: true }, supFalse: { value: 'value2', enumerable: false } }) proto[Symbol('supSymbol')] = 'supSymbol' console.log(proto) // { // supTrue: "value", // Symbol(supSymbol): "supSymbol", // supFalse: "value2" // } let obj = Object.create(proto, { ownTrue: { value: 'value1', enumerable: true }, ownFalse: { value: 'value2', enumerable: false } }) obj[Symbol('ownSymbol')] = 'ownSymbol' // ok,obj可用
for (const key in obj) { console.log(key) } // subTrue, ownTrue
能夠看到for in
枚舉了包括原型鏈在內的全部可枚舉屬性
Object.keys(obj) // ["ownTrue"]
能夠看到返回了一個只包含自身可枚舉屬性鍵的數組。
Object.getOwnPropertyNames(obj) // ["ownTrue", "ownFalse"]
能夠看到返回了一個包含自身全部非symbol
的屬性鍵的數組。
由此也能夠看到symbol
類型的屬性的「隱蔽性」
針對 獲取symbol
可以使用此方法。
雖然這個不是Object
的方法
可是能夠用來獲取自身全部屬性鍵
Reflect.ownKeys(obj) // ["ownTrue", "ownFalse", Symbol(ownSymbol)]
按照權限從大到小排列
做用:將對象變的不可擴展,不可添加新的屬性。
做用:將對象「密封」,不可添加新屬性,屬性的configurable
置爲false
,writable
爲true
的屬性仍然能夠被從新賦值。
權限:僅可對writable
爲true
的屬性進行賦值。
做用:徹底「鎖死」,不能作任何修改。
權限:0。
須要注意的是,上述三個api都是對原有對象的操做,並不會返回一個新的對象。
let obj = {} Object.preventExtensions(obj) === obj // true Object.seal(obj) === obj // true Object.freeze(obj) === obj // true
能夠說writable
,configurable
這些屬性描述符是針對對象的屬性作出的限制或者保護。
那麼Object.seal()
,Object.preventExtensions()
,Object.freeze()
就是對對象自己作出限制或者保護。
同時咱們也知道在ES6中使用const
能夠聲明一個"常量",可是要注意的是const
確保的只是指針的不可更改。好比:
const obj = {key: 'value1'} obj.key = 'value2' // 可完成 obj = {key2: 'value2'} // 更改指針,拋出異常
針對對象,此時就能夠使用上述三個把對象關起來的api。