06-可配置的
可配置的
控制该字段是否可以从对象中删除,或者字段的属性是否可以被更改。
可以使用 Object.defineProperty 来控制字段的属性,它可以创建一个新的字段,或者更改已有的字段(只要该字段是可配置的)。
例如,如果想让obj中的foo属性变成只读的,就可以使用 Object.defineProperty :
Object.defineProperty(obj, 'foo', { writable: false });
此时,如果试图给foo赋值,程序就会报错:
obj.foo = 3;
// TypeError: Cannot assign to read only property 'foo' of [object Object]
在严格模式下试图给一个只读字段赋值会引发错误。在非严格模式下,虽然赋值会失败,但程序不会报错。
还可以使用 Object.defineProperty 给对象添加新字段。这对有属性的字段来说格外有用,不同于数据属性,没有其他办法能在对象被创建后向其添加存取器属性。下面来给obj添加一个color属性(简单起见,这次没有使用符号,也省略了校验)。
Object.defineProperty(obj, 'color', {
get: function() { return this.color; },
set: function(value) { this.color = value; },
});
要创建一个数据属性,将value属性传入方法 Object.defineProperty 即可。下面给 obj 添加 name 和 greet 属性:
Object.defineProperty(obj, 'name', {
value: 'Cynthia',
});
Object.defineProperty(obj, 'greet', {
value: function() { return 'Hello, my name is ${this.name}!'; }
});
Object.defineProperty 的一个常见用法是在数组中将属性设为不可枚举的。前面已经提到过,在数组中使用字符串属性或符号属性不是一个明智的做法(因为它跟数组的用法是相反的),不过如果在使用时认真一些,并且考虑周全,它还是很有用的。虽然在数组中使用 for...in 或者 Object.keys 时也会让人灰心丧气(除非使用for、for...of或者 Array.prototype.forEach ),而也没法阻止别人这么做。所以,如果在数组中添加了非数值属性,那么应该将其设置为不可枚举的,从而防止有人(不听劝地)使用 for..in 或者 Object.keys 。下面来看一个往数组中添加 sum 和 avg 方法的例子:
const arr = [3, 1.5, 9, 2, 5.2];
arr.sum = function() { return this.reduce((a, x) => a+x); }
arr.avg = function() { return this.sum()/this.length; }
Object.defineProperty(arr, 'sum', { enumerable: false });
Object.defineProperty(arr, 'avg', { enumerable: false });
也可以每次在添加属性的时候设置:
const arr = [3, 1.5, 9, 2, 5.2];
Object.defineProperty(arr, 'sum', {
value: function() { return this.reduce((a, x) => a+x); },
enumerable: false
});
Object.defineProperty(arr, 'avg', {
value: function() { return this.sum()/this.length; },
enumerable: false
});
最后,还有一个方法:Object.defineProperties(注意这是复数的),它接收一个将属性名和其定义映射起来的对象。可以这样重写之前的例子:
const arr = [3, 1.5, 9, 2, 5.2];
Object.defineProperties(arr,
sum: {
value: function() { return this.reduce((a, x) => a+x); },
enumerable: false
}),
avg: {
value: function() { return this.sum()/this.length; },
enumerable: false
})
);
在严格模式下试图给一个只读字段赋值会引发错误。在非严格模式下,虽然赋值会失败,但程序不会报错。