源碼地址javascript
Object.defineProperty(對象,屬性,屬性描述符) 用於在一個對象上定義一個新的屬性,或者修改一個對象現有的屬性,並返回這個對象。html
屬性 | 默認值 | 說明 |
---|---|---|
configurable | false | 描述屬性是否能夠被刪除,默認爲 false |
enumerable | false | 描述屬性是否能夠被for...in或Object.keys枚舉,默認爲 false |
writable | false | 描述屬性是否能夠修改,默認爲 false |
get | undefined | 當訪問屬性時觸發該方法,默認爲undefined |
set | undefined | 當屬性被修改時觸發該方法,默認爲undefined |
value | undefined | 屬性值,默認爲undefined |
// demo01-default.html // Object.defineProperty(對象,屬性,屬性描述符) var obj = {}; console.log('obj:', obj); // 默認不可刪除,不可枚舉,不可修改 Object.defineProperty(obj, 'name', { value: 'Jameswain' }); console.log('obj默認值:', obj); delete obj.name; console.log('obj刪除後:', obj); console.log('obj枚舉:', Object.keys(obj)); obj.name = '詹姆斯,韋恩'; console.log('obj修改後:', obj); // 不能從新定義,會報重複定義錯誤: Uncaught TypeError: Cannot redefine property: name Object.defineProperty(obj, 'name', { value: '詹姆斯,韋恩' });
運行結果:java
從運行結果能夠發現,使用Object.defineProperty()定義的屬性,默認是不能夠被修改,不能夠被枚舉,不能夠被刪除的。能夠與常規的方式定義屬性對比一下:若是不使用Object.defineProperty()定義的屬性,默認是能夠修改、枚舉、刪除的:node
const obj = {}; obj.name = 'Jameswain'; console.log('枚舉:', Object.keys(obj)); obj.name = '詹姆斯-韋恩'; console.log('修改:', obj); delete obj.name; console.log('刪除:', obj);
// JavaScript/Object.defineProperty/demo02-descriptor.html const o = {}; Object.defineProperty(o, 'name', { value: 'Jameswain', // name屬性值 writable: true, // 能夠被修改 enumerable: true, // 能夠被枚舉 configurable: true, // 能夠被刪除 }); console.log(o); console.log('枚舉:', Object.keys(o)); o.name = '詹姆斯-韋恩'; console.log('修改:', o); Object.defineProperty(o, 'name', { value: 'Po' }); console.log('修改:', o); delete o.name; console.log('刪除:', o);
運行結果:git
⚠️注意:若是writable爲false,configurable爲true時,經過o.name = "詹姆斯-韋恩"是沒法修改爲功的,可是使用Object.defineProperty()修改是能夠成功的代碼以下:github
const o = {}; Object.defineProperty(o, 'name', { value: 'Jameswain', // name屬性值 writable: false // 不可被修改 enumerable: true, // 能夠被枚舉 configurable: true, // 能夠被刪除 }); console.log(o); console.log('枚舉:', Object.keys(o)); o.name = '詹姆斯-韋恩'; console.log('修改:', o); Object.defineProperty(o, 'name', { value: 'Po' }); console.log('修改:', o); delete o.name; console.log('刪除:', o);
⚠️注意:若是writable和configurable都爲false時,若是使用Object.defineProperty()修改屬性值會報錯:Cannot redefine property: name數組
const o = {}; Object.defineProperty(o, 'name', { value: 'Jameswain', // name屬性值 writable: false, // 不可被修改 enumerable: true, // 能夠被枚舉 configurable: false, // 不可被刪除 }); console.log(o); console.log('枚舉:', Object.keys(o)); o.name = '詹姆斯-韋恩'; console.log('修改:', o); Object.defineProperty(o, 'name', { value: 'Po' }); console.log('修改:', o); delete o.name; console.log('刪除:', o);
// JavaScript/Object.defineProperty/demo03-enumerable.html const o = {}; Object.defineProperty(o, 'name', { value: 'Jameswain', enumerable: true }); Object.defineProperty(o, 'trim', { value: (str) => { return str.trim() }, enumerable: false }); Object.defineProperty(o, 'email', { value: 'Jameswain@163.com' }); o.skill = 'node.js'; console.log('枚舉:', Object.keys(o)); console.log('trim: ', o.trim(' 8888 ') + '1') console.log(`o.propertyIsEnumerable('name'): `, o.propertyIsEnumerable('name')); console.log(`o.propertyIsEnumerable('trim'): `, o.propertyIsEnumerable('trim')); console.log(`o.propertyIsEnumerable('email'): `, o.propertyIsEnumerable('email'));
⚠️注意:設置set或者get,就不能在設置value和wriable,不然會報錯函數
const o = { __name: '' }; Object.defineProperty(o, 'name', { enumerable: true, configurable: true, // writable: true, // 若是設置了get或者set,writable和value屬性必須註釋掉 // value: '', // writable和value沒法與set和get共存 get: function () { // 若是設置了get 或者 set 就不能設置writable和value console.log('get', this); return 'My name is ' + this.__name; }, set: function (newVal) { localStorage.setItem('name', newVal); console.log('set', newVal); this.__name = newVal; } }); console.log(o); o.name = 'Jameswain'; o.name; console.log(o); o.name = '詹姆斯-韋恩'; console.log(o);
咱們能夠利用set和get實現數據驅動視圖變化功能,主要經過監聽屬性,屬性變化時更新視圖,獲取數據從視圖中獲取:this
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>set & get 數據驅動視圖</title> </head> <body> <div id="name"></div> <div id="skills"></div> <script type="text/javascript"> const profile = {}; Object.defineProperty(profile, 'name', { enumerable: true, configurable: true, get: function () { return document.querySelector('#name').innerHTML; }, set: function (newVal) { document.querySelector('#name').innerHTML = newVal; } }); Object.defineProperty(profile, 'skills', { get: () => document.querySelector('#skills').innerHTML.split(','), set: newVal => document.querySelector('#skills').innerHTML = newVal.toString() }); </script> </body> </html>
運行結果:spa
從運行結果中,咱們能夠發現profile.skills屬性是一個數組,若是直接更新整個數組內容是能夠驅動視圖變化的,可是若是更新數組對象中的某個元素是不會觸發set函數的。