您好,登錄后才能下訂單哦!
=與Object.defineProperty
為JavaScript對象新增或者修改屬性,有兩種不同方式:直接使用=賦值或者使用Object.defineProperty()定義。如下:
// 示例1 var obj = {}; // 直接使用=賦值 obj.a = 1; // 使用Object.defineProperty定義 Object.defineProperty(obj, "b", { value: 2 }); console.log(obj) // 打印"{a: 1, b: 2}"
這樣看兩者似乎沒有區別,對吧?但是,如果使用Object.getOwnPropertyDescriptor()查看obj.a與obj.b的屬性的描述描述符(property descriptor)時,會發現=與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}"
可知,使用=賦值時,屬性的屬性描述符value是可以修改的,而writable、enumerable和configurable都為true。
而使用Object.defineProperty()定義的屬性的屬性描述符writable、enumerable和configurable默認值為false,但是都可以修改。對于writable、enumerable和configurable的含義,從名字就不難猜中,后文也會詳細介紹。
使用=賦值,等價于使用Object.defineProperty()定義時,同時將writable、enumerable和configurable設為true。代碼示例3和4是等價的:
// 示例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()定義時若只定義value,則writable、enumerable和configurable默認值為false。代碼示例5和6是等價的:
// 示例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,導致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"
若在嚴格模式(“use strict”)下,示例7中的代碼會報錯,下文可見。
writable
writable為false時,屬性不能再次賦值,嚴格模式下會報錯“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 = "云麒"; // 報錯“Uncaught TypeError: Cannot assign to read only property 'name' of object '#<Object>'”
writable為true時,屬性可以賦值,這一點讀者不妨自行測試。
enumerable
enumerable為false時,屬性不能遍歷:
// 示例9 "use strict" var obj = {}; Object.defineProperty(obj, "name", { value: "Fundebug", writable: true, enumerable: false, configurable: true }); console.log(Object.keys(obj)) // 打印"[]"
enumerable為true時,屬性可以遍歷,這一點讀者不妨自行測試。
configurable
enumerable為false時,屬性不能刪除,嚴格模式下會報錯“Cannot delete property”:
// 示例10 "use strict" var obj = {}; Object.defineProperty(obj, "name", { value: "Fundebug", writable: true, enumerable: true, configurable: false }); delete obj.name // 報錯“Uncaught TypeError: Cannot delete property 'name' of #<Object>”
enumerable為true時,屬性可以刪除,這一點讀者不妨自行測試。
writable與configurable
當writable與enumerable同時為false時,屬性不能重新使用Object.defineProperty()定義,嚴格模式下會報錯“Cannot redefine property”:
// 示例11 "use strict" var obj = {}; Object.defineProperty(obj, "name", { value: "Fundebug", writable: false, configurable: false }) Object.defineProperty(obj, "name", { value: "云麒" }) // 報錯“Uncaught TypeError: Cannot redefine property: name”
當writable或者enumerable為true時,屬性可以重新使用Object.defineProperty()定義,這一點讀者不妨自行測試。
本文所有代碼示例都在Chrome 67上測試。
參考
Object.defineProperty()
Object.getOwnPropertyDescriptor()
StackOverflow: Why can't I redefine a property in a Javascript object?
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。