JavaScript的Object.defineProperty詳解
=與Object.defineProperty
為JavaScript對(duì)象新增或者修改屬性,有兩種不同方式:直接使用=賦值或者使用Object.defineProperty()定義。如下:
// 示例1 var obj = {}; // 直接使用=賦值 obj.a = 1; // 使用Object.defineProperty定義 Object.defineProperty(obj, "b", { value: 2 }); console.log(obj) // 打印"{a: 1, b: 2}"
這樣看兩者似乎沒有區(qū)別,對(duì)吧?但是,如果使用Object.getOwnPropertyDescriptor()查看obj.a與obj.b的屬性的描述描述符(property descriptor)時(shí),會(huì)發(fā)現(xiàn)=與Object.defineProperty并不一樣:
// 示例2 var obj = {}; obj.a = 1; Object.defineProperty(obj, "b", { value: 2 }); console.log(Object.getOwnPropertyDescriptor(obj, "a")); // 打印"{value: 1, writable: true, enumerable: true, configurable: true}" console.log(Object.getOwnPropertyDescriptor(obj, "b")); // 打印"{value: 2, writable: false, enumerable: false, configurable: false}"
可知,使用=賦值時(shí),屬性的屬性描述符value是可以修改的,而writable、enumerable和configurable都為true。
而使用Object.defineProperty()定義的屬性的屬性描述符writable、enumerable和configurable默認(rèn)值為false,但是都可以修改。對(duì)于writable、enumerable和configurable的含義,從名字就不難猜中,后文也會(huì)詳細(xì)介紹。
使用=賦值,等價(jià)于使用Object.defineProperty()定義時(shí),同時(shí)將writable、enumerable和configurable設(shè)為true。代碼示例3和4是等價(jià)的:
// 示例3 var obj = {}; obj.name = "Fundebug"; console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: true, enumerable: true, configurable: true}
// 示例4 var obj = {}; Object.defineProperty(obj, "name", { value: "Fundebug", writable: true, enumerable: true, configurable: true }); console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: true, enumerable: true, configurable: true}
Object.defineProperty()
使用Object.defineProperty()定義時(shí)若只定義value,則writable、enumerable和configurable默認(rèn)值為false。代碼示例5和6是等價(jià)的:
// 示例5 var obj = {}; Object.defineProperty(obj, "name", { value: "Fundebug" }); console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: false, enumerable: false, configurable: false}
// 示例6 var obj = {}; Object.defineProperty(obj, "name", { value: "Fundebug", writable: false, enumerable: false, configurable: false }); console.log(Object.getOwnPropertyDescriptor(obj, "name")); // 打印{value: "Fundebug", writable: false, enumerable: false, configurable: false}
由于writable、enumerable和configurable都是false,導(dǎo)致obj.name屬性不能賦值、不能遍歷而且不能刪除:
// 示例7 var obj = {}; Object.defineProperty(obj, "name", { value: "Fundebug" }); // writable為false,無法賦值 obj.name = "云麒"; console.log(obj.name); // 打印"Fundebug" // enumerable為false,無法遍歷 console.log(Object.keys(obj)); // 打印"[]" // configurable為false,無法刪除 delete obj.name; console.log(obj.name); // 打印"Fundebug"
若在嚴(yán)格模式(“use strict”)下,示例7中的代碼會(huì)報(bào)錯(cuò),下文可見。
writable
writable為false時(shí),屬性不能再次賦值,嚴(yán)格模式下會(huì)報(bào)錯(cuò)“Cannot assign to read only property”
// 示例8 "use strict" var obj = {}; Object.defineProperty(obj, "name", { value: "Fundebug", writable: false, enumerable: true, configurable: true }); obj.name = "云麒"; // 報(bào)錯(cuò)“Uncaught TypeError: Cannot assign to read only property 'name' of object '#<Object>'”
writable為true時(shí),屬性可以賦值,這一點(diǎn)讀者不妨自行測(cè)試。
enumerable
enumerable為false時(shí),屬性不能遍歷:
// 示例9 "use strict" var obj = {}; Object.defineProperty(obj, "name", { value: "Fundebug", writable: true, enumerable: false, configurable: true }); console.log(Object.keys(obj)) // 打印"[]"
enumerable為true時(shí),屬性可以遍歷,這一點(diǎn)讀者不妨自行測(cè)試。
configurable
enumerable為false時(shí),屬性不能刪除,嚴(yán)格模式下會(huì)報(bào)錯(cuò)“Cannot delete property”:
// 示例10 "use strict" var obj = {}; Object.defineProperty(obj, "name", { value: "Fundebug", writable: true, enumerable: true, configurable: false }); delete obj.name // 報(bào)錯(cuò)“Uncaught TypeError: Cannot delete property 'name' of #<Object>”
enumerable為true時(shí),屬性可以刪除,這一點(diǎn)讀者不妨自行測(cè)試。
writable與configurable
當(dāng)writable與enumerable同時(shí)為false時(shí),屬性不能重新使用Object.defineProperty()定義,嚴(yán)格模式下會(huì)報(bào)錯(cuò)“Cannot redefine property”:
// 示例11 "use strict" var obj = {}; Object.defineProperty(obj, "name", { value: "Fundebug", writable: false, configurable: false }) Object.defineProperty(obj, "name", { value: "云麒" }) // 報(bào)錯(cuò)“Uncaught TypeError: Cannot redefine property: name”
當(dāng)writable或者enumerable為true時(shí),屬性可以重新使用Object.defineProperty()定義,這一點(diǎn)讀者不妨自行測(cè)試。
本文所有代碼示例都在Chrome 67上測(cè)試。
參考
Object.getOwnPropertyDescriptor()
StackOverflow: Why can't I redefine a property in a Javascript object?
相關(guān)文章
用js提交表單解決一個(gè)頁面有多個(gè)提交按鈕的問題
這篇文章主要介紹了用js提交表單解決一個(gè)頁面有多個(gè)提交按鈕的問題,主要是判斷是否為提交文本,然后再執(zhí)行相應(yīng)的動(dòng)作,需要的朋友可以參考下2014-09-09Javascript腳本實(shí)現(xiàn)靜態(tài)網(wǎng)頁加密實(shí)例代碼
這篇文章介紹了Javascript腳本實(shí)現(xiàn)靜態(tài)網(wǎng)頁加密實(shí)例代碼,有需要的朋友可以參考一下2013-11-11js原生代碼實(shí)現(xiàn)輪播圖的實(shí)例講解
下面小編就為大家?guī)硪黄猨s原生代碼實(shí)現(xiàn)輪播圖的實(shí)例講解。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07uni-app實(shí)現(xiàn)獲取驗(yàn)證碼倒計(jì)時(shí)功能
這篇文章主要為大家詳細(xì)介紹了uni-app實(shí)現(xiàn)獲取驗(yàn)證碼倒計(jì)時(shí)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11DVA框架統(tǒng)一處理所有頁面的loading狀態(tài)
dva 有一個(gè)管理 effects 執(zhí)行的 hook,并基于此封裝了 dva-loading 插件。下面通過本文給大家分享DVA框架統(tǒng)一處理所有頁面的loading狀態(tài),感興趣的朋友一起看看吧2017-08-08JavaScript字符串轉(zhuǎn)換數(shù)字的方法
這篇文章主要介紹了JavaScript字符串轉(zhuǎn)換數(shù)字的方法,文章圍繞JavaScript字符串轉(zhuǎn)換數(shù)字的相關(guān)資料展開全文內(nèi)容,需要的小伙伴可以參考一下2021-12-12JS實(shí)現(xiàn)隨機(jī)顏色的3種方法與顏色格式的轉(zhuǎn)化
隨機(jī)顏色和顏色格式是我們?cè)陂_發(fā)中經(jīng)常要用到的一個(gè)小功能,網(wǎng)上相關(guān)的資料也很多,想著有必要總結(jié)一下自己的經(jīng)驗(yàn)。所以這篇文章主要介紹了JS實(shí)現(xiàn)隨機(jī)顏色的3種方法與顏色格式的轉(zhuǎn)化,需要的朋友可以參考借鑒,下面來一起看看吧。2017-01-01一個(gè)報(bào)數(shù)游戲js版(約瑟夫環(huán)問題)
隨便給一個(gè)數(shù) 比如100,那么從1到100圍成一個(gè)圓圈,然后就類似123123報(bào)數(shù)一樣逢3就舍掉,一直這樣輪詢 那么最后剩下來的那個(gè)數(shù)是多少?2010-08-08