概述以及定义:
- JavaScript 提供了一个内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。
- 这个内部数据结构称为“属性描述对象”(attributes object)。每个属性都有自己对应的属性描述对象,保存该属性的一些元信息。
属性描述对象有以下六个元属性(一个代码块)来描述对象的属性:
1 | { |
修改属性描述符
value
:该属性的属性值1
2
3
4
5
6
7
8var obj = {}//声明一个空对象
obj.p = 123;//声明obj的一个属性p
Object.getOwnPropertyDescriptor(obj, 'p').value;//通过Object.getOwnPropertyDescriptor()函数获取
//123
Object.defineProperty(obj,'p',{value:456});//通过Object.defineProperty()对属性value进行修改
//456writable
:布尔值,决定该属性是否可改变,默认true1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var obj = {};
Object.defineProperty(obj,'a',{
value: 37,
writable: false,//修改该属性对象描述中的writable为不可修改
});
obj.a//37
obj.a = 23;
//1.正常模式下上一行代码修改对象属性描述对象的writable值为false的操作不会报错,但是严格模式下任何赋值行为都会报错
//2.接第一点如果,因为子对象继承该父对象,子对象将无法自定义这个属性,也就是说,在严格模式下,父对象定义好了writable的值而子对象修改writable的值会报错
//3.接上面两点,有一个规避方法,就是通过覆盖属性描述对象
obj.a//无法被修改,所以仍然为37enumerable
:布尔值,表示该属性是否可遍历,默认为true1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19var obj = {};
Object.defineProperty(obj, 'x', {
value: 123,
enumerable: false
});
obj.x // 123
for (var key in obj) {
console.log(key);
}
// undefined
//enumerable为false,下面三个操作不会取到该属性。
for..in循环(for...in循环包括继承的属性)
Object.keys方法(Object.keys方法不包括继承的属性)
JSON.stringify方法configurable
:布尔值,表示该属性是否可遍历,默认为true,设置为false会使得某些操作(for..in…或者Object.keys())跳过该属性1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25//1.如果对象的属性描述对象中的configurable属性被设为了false值,那么相关的这个对象中的configurable为false时,writable、enumerable和configurable都不能被修改了。(浅不变性)
//2.value属性的情况比较特殊。只要writable和configurable有一个为true,就允许改动value
var obj = Object.defineProperty({}, 'p', {
value: 1,
writable: false,
enumerable: false,
configurable: false
});
Object.defineProperty(obj, 'p', {writable: true})
// TypeError: Cannot redefine property: p
//3.writable属性只有在false改为true时会报错,true改为false是允许的。
Object.defineProperty(obj, 'p', {enumerable: true})
// TypeError: Cannot redefine property: p
Object.defineProperty(obj, 'p', {configurable: true})
// TypeError: Cannot redefine property: p
Object.defineProperty(obj, 'p', {value: 2})
// TypeError: Cannot redefine property: p
//4.并且可配置性决定了目标属性是否可以被删除(delete),configurable是true,就可以被删除,否则就不行
对象常量
也就是说,上面//1.的obj.p
属性设置成writable:false,configurable:false
后,这个对象的这个属性就变成了常量,不可修改,不可删除,不可定义
- 存取器:
get
:是一个函数,表示该属性的取值函数(getter),默认为undefinedset
:是一个函数,表示该函数的存值函数(setter),默认为undefined1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27var obj = Object.defineProperty({}, 'p', {
get: function () {
return 'getter';
},
set: function (value) {
console.log('setter: ' + value);
}
});
//1.或者
var obj = {
get p() {
return 'getter';
},
set p(value) {
console.log('setter:' + value);
}
};
2.两种写法区别:第一种写法,属性p的configurable和enumerable都为false,从而导致属性p是不可遍历的;第二种写法,属性p的configurable和enumerable都为true,因此属性p是可遍历的
3.实际开发中,第二种方法更加常用
4.注意,取值函数get不能接受参数,存值函数set只能接受一个参数(即属性的值)
obj.p // "getter"
obj.p = 123 // "setter: 123"
禁止扩展
如果我们不想这个对象添加更多的属性,那么可以使用Object.preventExtensions()方法禁止扩展
1 | var obj={a:2}; |
密封
密封就是禁止扩展的升级版,Object.seal()方法使得一个对象既无法添加新属性,也无法删除旧属性:
1 | var obj = { p: 'hello' }; |
冻结
冻结就是密封的升级版,Object.freeze方法可以使得一个对象无法添加新属性、无法删除旧属性、也无法改变属性的值,使得这个对象实际上变成了常量
1 | var obj = { |
参考资料:
https://wangdoc.com/javascript/stdlib/attributes.html
https://juejin.cn/post/6898684702186717197