源码地址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函数的。