Object.defineProperty()
语法
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
Object.defineProperty(obj, prop, descriptor)
- obj
要定义属性的对象。 - prop
要定义或修改的属性的名称 - descriptor
要定义或修改的属性描述符。
规则
- 第一次进行赋值操作(a.b = xx or a[b] = xx or a = { b: xxx }),相当于使用 Object.defineProperty(a, ‘b’ ,{value: xxx, configurable: true, enumerable: true, writable: true})
- 首次使用 Object.defineProperty(a, ‘b’ ,{value: xxx}) 为对象添加一个值,等价于 Object.defineProperty(a, ‘b’ ,{value: xxx, configurable: false, enumerable: false, writable: false})
- 首次使用 Object.defineProperty 为对象添加一个值,之后再次使用 Object.defineProperty 修改对象属性的描述,只会修改本次配置中有的描述符,其它的描述符会继承本次修改前的描述符值,而不是修改为默认值
- configurable 为 false 时,configurable 不能变为 true
- configurable 为 false 时,不可以更改enumerable,true => false; false => true 都不可以
- configurable 为 false 时,writable 为 true ,可以更改value,否则不可以更改value
- configurable 为 false 时,可以更改 writable , true => false 可以, false => true 不可以
- configurable 为 true 时,configurable 可以变为false
- configurable 为 true 时,可以更改 enumerable ,true => false; false => true 都可以
- configurable 为 true 时,可以更改value
- configurable 为 true 时,可以更改 writable , true => false; false => true 都可以
- 赋值操作(a.b = xx or a[b] = xx)只有在 writable 为 true 时可以,无论 configurable 是否为true
- 修改 value 值的方式改变属性值,在 writable 为 true 或者 configurable 为 true 时都可以
- 当 configurable 为true时,可以从对应的对象上删除该属性
1. 第一次进行赋值操作(a.b = xx or a[b] = xx or a = { b: xxx }),相当于使用 Object.defineProperty(a, ‘b’ ,{value: xxx, configurable: true, enumerable: true, writable: true})
let a = {
b: 1
};
Object.getOwnPropertyDescriptor(a, 'b'); // { value: 1, writable: true, enumerable: true, configurable: true }
2. 首次使用 Object.defineProperty(a, ‘b’ ,{value: xxx}) 为对象添加一个值,等价于 Object.defineProperty(a, ‘b’ ,{value: xxx, configurable: false, enumerable: false, writable: false})
let a = {};
Object.defineProperty(a, 'b', {
value: 1
});
Object.getOwnPropertyDescriptor(a, 'b'); // { value: 1, writable: false, enumerable: false, configurable: false }
3. 首次使用 Object.defineProperty 为对象添加一个值,之后再次使用 Object.defineProperty 修改对象属性的描述,只会修改本次配置中有的描述符,其它的描述符会继承本次修改前的描述符值,而不是修改为默认值
let a = {};
Object.defineProperty(a, 'b', {
value: 1,
writable: true,
enumerable: true,
configurable: true
});
console.log(a.b); // 1
Object.defineProperty(a, 'b', {
value: 2
});
console.log(a.b); // 2
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: 2, writable: true, enumerable: true, configurable: true}
4. configurable 为 false 时,configurable 不能变为 true
let a = {};
Object.defineProperty(a, 'b', {
configurable: false
});
// Uncaught TypeError: Cannot redefine property: b
Object.defineProperty(a, 'b', {
configurable: true
});
5. configurable 为 false 时,不可以更改 enumerable ,true => false; false => true 都不可以
let a = {};
Object.defineProperty(a, 'b', {
configurable: false,
enumerable: true
});
// Uncaught TypeError: Cannot redefine property: b
Object.defineProperty(a, 'b', {
configurable: false,
enumerable: false
});
let a = {};
Object.defineProperty(a, 'b', {
configurable: false,
enumerable: false
});
// Uncaught TypeError: Cannot redefine property: b
Object.defineProperty(a, 'b', {
configurable: false,
enumerable: true
});
6. configurable 为 false 时, writable 为 true ,可以更改value,否则不可以更改value
let a = {};
Object.defineProperty(a, 'b', {
value: 1,
configurable: false,
writable: true
});
console.log(a.b); // 1
Object.defineProperty(a, 'b', {
value: 2
});
console.log(a.b); // 1
let a = {};
Object.defineProperty(a, 'b', {
value: 1,
configurable: false,
writable: false
});
console.log(a.b); // 1
// Uncaught TypeError: Cannot redefine property: b
Object.defineProperty(a, 'b', {
value: 2
});
console.log(a.b);
7. configurable 为 false 时,可以更改 writable , true => false 可以, false => true 不可以
let a = {};
Object.defineProperty(a, 'b', {
configurable: false,
writable: true
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: true, enumerable: false, configurable: false}
Object.defineProperty(a, 'b', {
configurable: false,
writable: false
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: false, enumerable: false, configurable: false}
let a = {};
Object.defineProperty(a, 'b', {
configurable: false,
writable: false
});
// Uncaught TypeError: Cannot redefine property: b
Object.defineProperty(a, 'b', {
configurable: false,
writable: true
});
8. configurable 为 true 时,configurable 可以变为false
let a = {};
Object.defineProperty(a, 'b', {
configurable: true
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: false, enumerable: false, configurable: true}
Object.defineProperty(a, 'b', {
configurable: false
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: false, enumerable: false, configurable: false}
9. configurable 为 true 时,可以更改 enumerable ,true => false; false => true 都可以
let a = {};
Object.defineProperty(a, 'b', {
configurable: true,
enumerable: true
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: false, enumerable: true, configurable: true}
Object.defineProperty(a, 'b', {
configurable: true,
enumerable: false
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: false, enumerable: false, configurable: true}
let a = {};
Object.defineProperty(a, 'b', {
configurable: true,
enumerable: false
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: false, enumerable: false, configurable: true}
Object.defineProperty(a, 'b', {
configurable: true,
enumerable: true
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: false, enumerable: true, configurable: true}
10. configurable 为 true 时,可以更改value
let a = {};
Object.defineProperty(a, 'b', {
configurable: true,
value: 1
});
console.log(a.b); // 1
Object.defineProperty(a, 'b', {
configurable: true,
value: 2
});
console.log(a.b); // 2
11. configurable 为 true 时,可以更改 writable , true => false; false => true 都可以
let a = {};
Object.defineProperty(a, 'b', {
configurable: true,
writable: true
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: true, enumerable: false, configurable: true}
Object.defineProperty(a, 'b', {
configurable: true,
writable: false
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: false, enumerable: false, configurable: true}
let a = {};
Object.defineProperty(a, 'b', {
configurable: true,
writable: false
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: false, enumerable: false, configurable: true}
Object.defineProperty(a, 'b', {
configurable: true,
writable: true
});
console.log(Object.getOwnPropertyDescriptor(a, 'b')); // {value: undefined, writable: true, enumerable: false, configurable: true}
12. 赋值操作(a.b = xx or a[b] = xx)只有在 writable 为 true 时可以,无论 configurable 是否为true
let a = {};
Object.defineProperty(a, 'b', {
value: 1,
writable: true,
configurable: true
});
console.log(a.b); // 1
a.b = 2;
console.log(a.b); // 2
Object.defineProperty(a, 'b', {
configurable: false
});
a.b = 3;
console.log(a.b); // 3
let a = {};
Object.defineProperty(a, 'b', {
value: 1,
writable: false,
configurable: true
});
console.log(a.b); // 1
a.b = 2;
console.log(a.b); // 1
Object.defineProperty(a, 'b', {
configurable: false
});
a.b = 3;
console.log(a.b); // 1
'use strict'
let a = {};
Object.defineProperty(a, 'b', {
value: 1,
writable: false,
configurable: true
});
console.log(a.b); // 1
// Uncaught TypeError: Cannot assign to read only property 'b' of object '#<Object>'
a.b = 2;
13. 修改 value 值的方式改变属性值,在 writable 为 true 或者 configurable 为 true 时都可以
let a = {};
Object.defineProperty(a, 'b', {
value: 1,
writable: true,
configurable: false
});
console.log(a.b); // 1
Object.defineProperty(a, 'b', {
value: 2
});
console.log(a.b); // 2
let a = {};
Object.defineProperty(a, 'b', {
value: 1,
writable: false,
configurable: true
});
console.log(a.b); // 1
Object.defineProperty(a, 'b', {
value: 2
});
console.log(a.b); // 2
14. 当 configurable 为true时,可以从对应的对象上删除该属性
let a = {};
Object.defineProperty(a, 'b', {
configurable: true
});
delete a.b // true
Object.defineProperty(a, 'c', {
configurable: false
});
delete a.c // false
'use strict'
let a = {};
Object.defineProperty(a, 'b', {
configurable: true
});
delete a.b // true
Object.defineProperty(a, 'c', {
configurable: false
});
// VM1417:12 Uncaught TypeError: Cannot delete property 'c' of #<Object>
delete a.c
描述符可拥有的键值
configurable | enumerable | value | writable | get | set | |
---|---|---|---|---|---|---|
数据描述符 | 可以 | 可以 | 可以 | 可以 | 不可以 | 不可以 |
存取描述符 | 可以 | 可以 | 不可以 | 不可以 | 可以 | 可以 |
如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常。
let a = {};
// VM1535:2 Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>
Object.defineProperty(a, 'b', {
value: 1,
set: () => {
}
});
get & set
var obj = {
//定义_x属性
_x : 1,
//定义x属性的getter
get x() { return this._x },
//定义x属性的setter
set x(value) {
if (typeof value != "number") throw new Error('请输入数字');
this._x = value; //赋值
}
};
console.log(obj.x); // 1
obj.x = 2;
console.log(obj.x); // 2
利用get&set实现双向数据绑定
<!DOCTYPE html>
<html>
<head>
<title>defineProperty双向数据绑定</title>
</head>
<body>
<p>
输出测试数据: <input type="text" id="input" />
</p>
<p id="show-area">
obj.val1值: {{obj.val1}}
</p>
<p>
更改obj.val1: <input type="text" id="change-obj-val1" />
</p>
</body>
<script type="text/javascript">
const inputEle = document.getElementById('input');
const obj = {};
let objShowText = document.getElementById('show-area').innerText;
function setValue(newValue) {
inputEle.value = newValue;
let innerText = document.getElementById('show-area').innerText;
document.getElementById('show-area').innerText = objShowText.replace('{{obj.val1}}', newValue)
}
// 添加代理
Object.defineProperty(obj, 'val1', {
get: () => {
},
set: (newValue) => {
// js 对象更改时更新页面
setValue(newValue);
}
});
// 监听页面输入,页面输入的话更新js对象
inputEle.addEventListener('keyup', (event) => {
obj.val1 = event.target.value;
});
// js对象更改同步页面显示
document.getElementById('change-obj-val1').addEventListener('keyup', (event) => {
obj.val1 = event.target.value;
});
</script>
</html>