Object的defineProperty和defineProperties這兩個(gè)方法在js中的重要性十分重要,主要功能就是用來(lái)定義或修改這些內(nèi)部屬性,與之相對(duì)應(yīng)的getOwnPropertyDescriptor和getOwnPropertyDescriptors就是獲取這行內(nèi)部屬性的描述。
下面文章我先介紹數(shù)據(jù)描述符和存取描述符的屬性代表的含義,然后簡(jiǎn)單介紹以上四個(gè)方法的基本功能,這些如果了解可直接跳過(guò),最后我會(huì)舉例擴(kuò)展及說(shuō)明各內(nèi)部屬性在各種場(chǎng)景下產(chǎn)生的實(shí)際效果,那才是這篇文章的核心內(nèi)容。本文章關(guān)于概念性的描述還是會(huì)盡量使用《javaScript高級(jí)教程》、MDN網(wǎng)站等概念,保證準(zhǔn)確和易于大家理解,講解部分則結(jié)合個(gè)人理解和舉例說(shuō)明。
數(shù)據(jù)(數(shù)據(jù)描述符)屬性
數(shù)據(jù)屬性有4個(gè)描述內(nèi)部屬性的特性
[[Configurable]]
表示能否通過(guò)delete刪除此屬性,能否修改屬性的特性,或能否修改把屬性修改為訪(fǎng)問(wèn)器屬性,如果直接使用字面量定義對(duì)象,默認(rèn)值為true。
[[Enumerable]]
表示該屬性是否可枚舉,即是否通過(guò)for-in循環(huán)或Object.keys()返回屬性,如果直接使用字面量定義對(duì)象,默認(rèn)值為true
[[Writable]]
能否修改屬性的值,如果直接使用字面量定義對(duì)象,默認(rèn)值為true
[[Value]]
該屬性對(duì)應(yīng)的值,默認(rèn)為undefined
訪(fǎng)問(wèn)器(存取描述符)屬性
訪(fǎng)問(wèn)器屬性也有4個(gè)描述內(nèi)部屬性的特性
[[Configurable]]
和數(shù)據(jù)屬性的[[Configurable]]一樣,表示能否通過(guò)delete刪除此屬性,能否修改屬性的特性,或能否修改把屬性修改為訪(fǎng)問(wèn)器屬性,如果直接使用字面量定義對(duì)象,默認(rèn)值為true
[[Enumerable]]
和數(shù)據(jù)屬性的[[Configurable]]一樣,表示該屬性是否可枚舉,即是否通過(guò)for-in循環(huán)或Object.keys()返回屬性,如果直接使用字面量定義對(duì)象,默認(rèn)值為true
[[GET]]
一個(gè)給屬性提供 getter 的方法(訪(fǎng)問(wèn)對(duì)象屬性時(shí)調(diào)用的函數(shù),返回值就是當(dāng)前屬性的值),如果沒(méi)有 getter 則為 undefined。該方法返回值被用作屬性值。默認(rèn)為 undefined
[[SET]]
一個(gè)給屬性提供 setter 的方法(給對(duì)象屬性設(shè)置值時(shí)調(diào)用的函數(shù)),如果沒(méi)有 setter 則為 undefined。該方法將接受唯一參數(shù),并將該參數(shù)的新值分配給該屬性。默認(rèn)為 undefined
創(chuàng)建/修改/獲取屬性的方法
YI、Object.defineProperty()
功能:
方法會(huì)直接在一個(gè)對(duì)象上定義一個(gè)新屬性,或者修改一個(gè)對(duì)象的現(xiàn)有屬性, 并返回這個(gè)對(duì)象。如果不指定configurable, writable, enumerable ,則這些屬性默認(rèn)值為false,如果不指定value, get, set,則這些屬性默認(rèn)值為undefined
語(yǔ)法: Object.defineProperty(obj, prop, descriptor)
obj: 需要被操作的目標(biāo)對(duì)象
prop: 目標(biāo)對(duì)象需要定義或修改的屬性的名稱(chēng)
descriptor: 將被定義或修改的屬性的描述符var obj = new Object(); Object.defineProperty(obj, 'name', { configurable: false, writable: true, enumerable: true, value: '張三' }) console.log(obj.name) //張三
ER、Object.defineProperties()
功能:
方法直接在一個(gè)對(duì)象上定義一個(gè)或多個(gè)新的屬性或修改現(xiàn)有屬性,并返回該對(duì)象。
語(yǔ)法:Object.defineProperties(obj,props)
obj : 將要被添加屬性或修改屬性的對(duì)象。
props : 該對(duì)象的一個(gè)或多個(gè)鍵值對(duì)定義了將要為對(duì)象添加或修改的屬性的具體配置var obj = new Object(); Object.defineProperties(obj, { name: { value: '張三', configurable: false, writable: true, enumerable: true }, age: { value: 18, configurable: true } }) console.log(obj.name, obj.age) // 張三, 18
SAN、Object.getOwnPropertyDescriptor()
功能:
該方法返回指定對(duì)象上的一個(gè)自有屬性對(duì)應(yīng)的屬性描述(自有屬性指的是直接賦予該對(duì)象的屬性,不需要從原型鏈上進(jìn)行查找的屬性)
語(yǔ)法: Object.getOwnPropertyDescriptor(obj, prop)//obj: 需要查找的目標(biāo)對(duì)象, prop: 目標(biāo)對(duì)象內(nèi)屬性名稱(chēng)var person = { name: '張三', age: 18 } var desc = Object.getOwnPropertyDescriptor(person, 'name'); console.log(desc) 結(jié)果如下 // { // configurable: true, // enumerable: true, // writable: true, // value: "張三" // }
SI、Object. getOwnPropertyDescriptors()
功能:所指定對(duì)象的所有自身屬性的描述符,如果沒(méi)有任何自身屬性,則返回空對(duì)象。
語(yǔ)法: Object.getOwnPropertyDescriptors(obj)//obj: 需要查找的目標(biāo)對(duì)象var person = { name: '張三', age: 18 } var desc = Object.getOwnPropertyDescriptors(person); console.log(desc) // age: { // value: 18, writable: true, enumerable: true, configurable: true} // name: { // value: "張三", writable: true, enumerable: true, configurable: true} // __proto__: Object
各種場(chǎng)景下描述符屬性的擴(kuò)展示例講解
.configurable
如果設(shè)置configurable屬性為false,則不可使用delete操作符(在嚴(yán)格模式下拋出錯(cuò)誤),
修改所有內(nèi)部屬性值會(huì)拋出錯(cuò)誤在對(duì)象中添加一個(gè)數(shù)據(jù)描述符屬性
var person = {}; Object.defineProperty(person, 'name', { configurable: false, value: 'John' }) ; delete person.name // 嚴(yán)格模式下拋出錯(cuò)誤 console.log(person.name) // 'John' 沒(méi)有刪除 Object.defineProperty(person, 'name', { configurable: true //報(bào)錯(cuò) }); Object.defineProperty(person, 'name', { enumerable: 2 //報(bào)錯(cuò) }); Object.defineProperty(person, 'name', { writable: true //報(bào)錯(cuò) }); Object.defineProperty(person, 'name', { value: 2 //報(bào)錯(cuò) });注意:以上是·最開(kāi)始定義屬性描述符·時(shí),writabl默認(rèn)為false,才會(huì)出現(xiàn)上述效果,如果writable定義為true, 則可以修改[[writable]]和[[value]]屬性值,修改另外兩個(gè)屬性值報(bào)錯(cuò):
var obj = {}; Object.defineProperty(obj, 'a', { configurable: false, writable: true, value: 1 }); Object.defineProperty(obj, 'a', { // configurable: true, //報(bào)錯(cuò) // enumerable: true, //報(bào)錯(cuò) writable: false, value: 2 }); var d = Object.getOwnPropertyDescriptor(obj, 'a') console.log(d); // { // value: 2, // writable: false, // }在對(duì)象中添加存取描述符屬性
var obj = {}; var aValue; //如果不初始化變量, 不給下面的a屬性設(shè)置值,直接讀取會(huì)報(bào)錯(cuò)aValue is not defined var b; Object.defineProperty(obj, 'a', { configurable : true, enumerable : true, get: function() { return aValue }, set: function(newValue) { aValue = newValue; b = newValue + 1 } }) console.log(b) // undefined console.log(obj.a) // undefined, 當(dāng)讀取屬性值時(shí),調(diào)用get方法,返回undefined obj.a = 2; // 當(dāng)設(shè)置屬性值時(shí),調(diào)用set方法,aValue為2 console.log(obj.a) // 2 讀取屬性值,調(diào)用get方法,此時(shí)aValue為2 console.log(b) // 3 再給obj.a賦值時(shí),執(zhí)行set方法,b的值被修改為2,額外說(shuō)一句,vue中的計(jì)算屬性就是利用setter來(lái)實(shí)現(xiàn)的注意:
- getter和setter可以不同時(shí)使用,但在嚴(yán)格模式下只使用一個(gè),會(huì)拋出錯(cuò)誤。
- 數(shù)據(jù)描述符與存取描述符不可以混用,否則會(huì)拋出錯(cuò)誤。
- 使用 var定義的任何變量,其
configurable屬性值都為false,定義對(duì)象也是一樣.
Writable
當(dāng)Writable為false(并且configurable為true),[value]可以通過(guò) defineProperty修改,但不能直接賦值修改。
var obj = {}; Object.defineProperty(obj, 'a', { configurable: true, enumerable: false, writable: false, value: 1 }); Object.defineProperty(obj, 'a', { configurable: false, enumerable: true, writable: false , value: 2 }); var d = Object.getOwnPropertyDescriptor(obj, 'a') console.log(d); // 結(jié)果如下 // { // value: 2, // writable: false, // enumerable: true, // configurable: false // } 但是如果直接復(fù)制修改 var obj = {} Object.defineProperty(obj, 'a', { configurable: true, enumerable: false, writable: false, value: 1 }); obj.a=2; var d = Object.getOwnPropertyDescriptor(obj, 'a') console.log(d); // 結(jié)果如下 // { // value: 1, // 沒(méi)有做出修改 // writable: false, // enumerable: true, // configurable: false // }
Enumerable
直接上例子
var obj = {}; Object.defineProperties(obj, { a: { value: 1, enumerable: false }, b: { value: 2, enumerable: true }, c: { value: 3, enumerable: false } }) obj.d = 4; //等同于 //Object.defineProperty(obj, 'd', { // configurable: true, // enumerable: true, // writable: true, // value: 4 //}) for(var key in obj) { console.log(key); // 打印一次b, 一次d, a和c屬性enumerable為false,不可被枚舉 } var arr = Object.keys(obj); console.log(arr); // ['b', 'd']
get 和 set
簡(jiǎn)易的數(shù)據(jù)雙向綁定
//html <body> <p> input1=> <input type="text" id="input1"> </p> <p> input2=> <input type="text" id="input2"> </p> <div> 我每次比input1的值加1=> <span id="span"></span> </div> </body> //js var oInput1 = document.getElementById('input1'); var oInput2 = document.getElementById('input2'); var oSpan = document.getElementById('span'); var obj = {}; Object.defineProperties(obj, { val1: { configurable: true, get: function() { oInput1.value = 0; oInput2.value = 0; oSpan.innerHTML = 0; return 0 }, set: function(newValue) { oInput2.value = newValue; oSpan.innerHTML = Number(newValue) ? Number(newValue) : 0 } }, val2: { configurable: true, get: function() { oInput1.value = 0; oInput2.value = 0; oSpan.innerHTML = 0; return 0 }, set: function(newValue) { oInput1.value = newValue; oSpan.innerHTML = Number(newValue)+1; } } }) oInput1.value = obj.val1; oInput1.addEventListener('keyup', function() { obj.val1 = oInput1.value; }, false) oInput2.addEventListener('keyup', function() { obj.val2 = oInput2.value; }, false)
原文鏈接地址:https://segmentfault.com/a/1190000011294519?utm_source=tag-newest#articleHeader15
如有疑問(wèn)請(qǐng)?zhí)砑游业奈⑿盘?hào):18231133236。歡迎交流!
更多內(nèi)容,請(qǐng)?jiān)L問(wèn)的我的個(gè)人博客:https://www.liugezhou.online.
您也可以關(guān)注我的個(gè)人公眾號(hào):【Dangerous Wakaka】