Object.defineProperty()講解
**Object.defineProperty()**
方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性抒痒,或者修改一個(gè)對(duì)象的現(xiàn)有屬性,并返回此對(duì)象。
備注:應(yīng)當(dāng)直接在 Object
構(gòu)造器對(duì)象上調(diào)用此方法材失,而不是在任意一個(gè) Object
類型的實(shí)例上調(diào)用蓝丙。
語法
Object.defineProperty(obj, prop, descriptor)
參數(shù)
-
obj
要定義屬性的對(duì)象。
-
prop
要定義或修改的屬性的名稱或 Symbol
疲憋。
-
descriptor
要定義或修改的屬性描述符凿渊。
返回值
被傳遞給函數(shù)的對(duì)象。
描述
該方法允許精確地添加或修改對(duì)象的屬性。通過賦值操作添加的普通屬性是可枚舉的埃脏,在枚舉對(duì)象屬性時(shí)會(huì)被枚舉到(for...in
或 Object.keys
方法)搪锣,可以改變這些屬性的值,也可以刪除
這些屬性彩掐。這個(gè)方法允許修改默認(rèn)的額外選項(xiàng)(或配置)构舟。默認(rèn)情況下,使用 Object.defineProperty()
添加的屬性值是不可修改(immutable)的堵幽。
對(duì)象里目前存在的屬性描述符有兩種主要形式:數(shù)據(jù)描述符和存取描述符狗超。數(shù)據(jù)描述符是一個(gè)具有值的屬性,該值可以是可寫的朴下,也可以是不可寫的努咐。存取描述符是由 getter 函數(shù)和 setter 函數(shù)所描述的屬性。一個(gè)描述符只能是這兩者其中之一殴胧;不能同時(shí)是兩者渗稍。
這兩種描述符都是對(duì)象。它們共享以下可選鍵值(默認(rèn)值是指在使用 Object.defineProperty()
定義屬性時(shí)的默認(rèn)值):
-
configurable
當(dāng)且僅當(dāng)該屬性的 configurable 鍵值為 true 時(shí)团滥,該屬性的描述符才能夠被改變竿屹,同時(shí)該屬性也能從對(duì)應(yīng)的對(duì)象上被刪除。
默認(rèn)為 false灸姊。
-
enumerable
當(dāng)且僅當(dāng)該屬性的 enumerable 鍵值為 true 時(shí)羔沙,該屬性才會(huì)出現(xiàn)在對(duì)象的枚舉屬性中。
默認(rèn)為 false厨钻。
數(shù)據(jù)描述符還具有以下可選鍵值:
-
value
該屬性對(duì)應(yīng)的值扼雏。可以是任何有效的 JavaScript 值(數(shù)值夯膀,對(duì)象诗充,函數(shù)等)。
默認(rèn)為 undefined
诱建。
-
writable
當(dāng)且僅當(dāng)該屬性的 writable
鍵值為 true
時(shí)蝴蜓,屬性的值,也就是上面的 value
俺猿,才能被賦值運(yùn)算符
改變茎匠。
默認(rèn)為 false
。
存取描述符還具有以下可選鍵值:
-
get
屬性的 getter 函數(shù)押袍,如果沒有 getter诵冒,則為 undefined
。當(dāng)訪問該屬性時(shí)谊惭,會(huì)調(diào)用此函數(shù)汽馋。執(zhí)行時(shí)不傳入任何參數(shù)侮东,但是會(huì)傳入 this
對(duì)象(由于繼承關(guān)系,這里的this
并不一定是定義該屬性的對(duì)象)豹芯。該函數(shù)的返回值會(huì)被用作屬性的值悄雅。
默認(rèn)為 undefined
。
-
set
屬性的 setter 函數(shù)铁蹈,如果沒有 setter宽闲,則為 undefined
。當(dāng)屬性值被修改時(shí)握牧,會(huì)調(diào)用此函數(shù)便锨。該方法接受一個(gè)參數(shù)(也就是被賦予的新值),會(huì)傳入賦值時(shí)的 this
對(duì)象我碟。
默認(rèn)為 undefined
放案。
描述符默認(rèn)值匯總
- 擁有布爾值的鍵 configurable、enumerable 和 writable 的默認(rèn)值都是 false矫俺。
- 屬性值和函數(shù)的鍵 value吱殉、get 和 set 字段的默認(rèn)值為 undefined。
如果一個(gè)描述符不具有 value
厘托、writable
友雳、get
和 set
中的任意一個(gè)鍵,那么它將被認(rèn)為是一個(gè)數(shù)據(jù)描述符铅匹。如果一個(gè)描述符同時(shí)擁有 value
或 writable
和 get
或 set
鍵押赊,則會(huì)產(chǎn)生一個(gè)異常。
記住包斑,這些選項(xiàng)不一定是自身屬性流礁,也要考慮繼承來的屬性。為了確認(rèn)保留這些默認(rèn)值罗丰,在設(shè)置之前神帅,可能要凍結(jié) Object.prototype
,明確指定所有的選項(xiàng)萌抵,或者通過 Object.create(null)
將 __proto__
(en-US) 屬性指向 null
找御。
示例
var o = {}; // 創(chuàng)建一個(gè)新對(duì)象
// 在對(duì)象中添加一個(gè)屬性與數(shù)據(jù)描述符的示例
Object.defineProperty(o, "a", {
value : 37,
writable : true,
enumerable : true,
configurable : true
});
// 對(duì)象 o 擁有了屬性 a,值為 37
// 在對(duì)象中添加一個(gè)設(shè)置了存取描述符屬性的示例
var bValue = 38;
Object.defineProperty(o, "b", {
// 使用了方法名稱縮寫(ES2015 特性)
// 下面兩個(gè)縮寫等價(jià)于:
// get : function() { return bValue; },
// set : function(newValue) { bValue = newValue; },
get() { return bValue; },
set(newValue) { bValue = newValue; },
enumerable : true,
configurable : true
});
o.b; // 38
// 對(duì)象 o 擁有了屬性 b绍填,值為 38
// 現(xiàn)在霎桅,除非重新定義 o.b,o.b 的值總是與 bValue 相同
// 數(shù)據(jù)描述符和存取描述符不能混合使用
Object.defineProperty(o, "conflict", {
value: 0x9f91102,
get() { return 0xdeadbeef; }
});
// 拋出錯(cuò)誤 TypeError: value appears only in data descriptors, get appears only in accessor descriptors
兼容性問題
重定義數(shù)組 Array
對(duì)象的 length
屬性
重定義數(shù)組的 length
屬性是可能的讨永,但是會(huì)受到一般的重定義限制滔驶。(length
屬性初始為 non-configurable,non-enumerable 以及 writable住闯。對(duì)于一個(gè)內(nèi)容不變的數(shù)組瓜浸,改變其 length
屬性的值或者使它變?yōu)?non-writable 是可能的澳淑。但是改變其可枚舉性和可配置性或者當(dāng)它是 non-writable 時(shí)嘗試改變它的值或是可寫性比原,這兩者都是不允許的插佛。)然而,并不是所有的瀏覽器都允許 Array.length
的重定義量窘。
在 Firefox 4 至 22 版本中雇寇,嘗試重定義數(shù)組的 length 屬性都會(huì)拋出 TypeError
異常。
一些版本的 Chrome 中蚌铜,Object.defineProperty()
在某些情況下會(huì)忽略不同于數(shù)組當(dāng)前length
屬性的length值锨侯。有些情況下改變可寫性并不起作用(也不拋出異常)。同時(shí)冬殃,比如Array.prototype.push
的一些數(shù)組操作方法也不會(huì)考慮不可讀的length屬性囚痴。
一些版本的 Safari 中,Object.defineProperty()
在某些情況下會(huì)忽略不同于數(shù)組當(dāng)前length
屬性的length值审葬。嘗試改變可寫性的操作會(huì)正常執(zhí)行而不拋出錯(cuò)誤深滚,但事實(shí)上并未改變屬性的可寫性。
只在Internet Explorer 9及以后版本和Firefox 23及以后版本中涣觉,才完整地正確地支持?jǐn)?shù)組 length
屬性的重新定義痴荐。目前不要依賴于重定義數(shù)組 length
屬性能夠起作用,或在特定情形下起作用官册。與此同時(shí)生兆,即使你能夠依賴于它,你也沒有合適的理由這樣做膝宁。