共计 4227 个字符,预计需要花费 11 分钟才能阅读完成。
简介
源码地址
Object.defineProperty(对象,属性,属性描述符) 用于在一个对象上定义一个新的属性,或者修改一个对象现有的属性,并返回这个对象。
demo01 – 属性描述符默认值
属性 | 默认值 | 说明 |
---|---|---|
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: '詹姆斯,韦恩'});
运行结果:
从运行结果可以发现,使用 Object.defineProperty() 定义的属性,默认是不可以被修改,不可以被枚举,不可以被删除的。可以与常规的方式定义属性对比一下:如果不使用 Object.defineProperty() 定义的属性,默认是可以修改、枚举、删除的:
const obj = {};
obj.name = 'Jameswain';
console.log('枚举:', Object.keys(obj));
obj.name = '詹姆斯 - 韦恩';
console.log('修改:', obj);
delete obj.name;
console.log('删除:', obj);
demo02 – 属性描述符
// 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);
运行结果:
⚠️注意:如果 writable 为 false,configurable 为 true 时,通过 o.name = “ 詹姆斯 - 韦恩 ” 是无法修改成功的,但是使用 Object.defineProperty() 修改是可以成功的代码如下:
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);
demo03 – enumerable
// 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'));
demo04 – set 和 get
⚠️注意:设置 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);
demo05 – set 和 get 数据驱动视图
我们可以利用 set 和 get 实现数据驱动视图变化功能,主要通过监听属性,属性变化时更新视图,获取数据从视图中获取:
<!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>
运行结果:
从运行结果中,我们可以发现 profile.skills 属性是一个数组,如果直接更新整个数组内容是可以驱动视图变化的,但是如果更新数组对象中的某个元素是不会触发 set 函数的。
正文完
发表至: javascript
2019-06-11