这是我参与8月更文挑战的第27天,活动详情查看: 8月更文挑战
序言
我们知道,对象可以存储属性。但是大多数时候,属性对我们来说只是一个简单的“键值”对。但对象属性实际上是更灵活且更强大的东西,我们今天就来看看属性的配置选项。
属性的标志
对象属性,除 value 外,还有三个特殊的特性,也就是所谓的属性标志:
- writable — 如果为 true,则值可以被修改,否则它是只可读的。
- enumerable — 如果为 true,则会被在循环中列出,否则不会被列出。
- configurable — 如果为 true,则此特性可以被删除,这些属性也可以被修改,否则不可以。
我们通常看不到它们。当我们创建一个属性时,它们默认都为 true。而且我们也可以随时更改它们。
如何获得属性标志
Object.getOwnPropertyDescriptor 方法允许查询有关属性的 完整 信息。
let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
obj 需要从中获取信息的对象。 propertyName 属性的名称。 返回值是一个所谓的“属性描述符”对象:它包含值和所有的标志。 例子:
let user = {
name: "coolFish"
};
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/* 属性描述符:
{
"value": "coolFish",
"writable": true,
"enumerable": true,
"configurable": true
}
*/
为了修改标志,我们可以使用 Object.defineProperty。
Object.defineProperty(obj, propertyName, descriptor)
obj,propertyName 要应用描述符的对象及其属性。 descriptor 要应用的属性描述符对象。 如果该属性存在,defineProperty 会更新其标志。否则,它会使用给定的值和标志创建属性;在这种情况下,如果没有提供标志,则会假定它是 false。
下例中,我们创建一个属性,他的所有属性默认为false
let user = {};
Object.defineProperty(user, "name", {
value: "coolFish"
});
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": "coolFish",
"writable": false,
"enumerable": false,
"configurable": false
}
*/
将它与上面的“以常用方式创建的” user.name 进行比较:现在所有标志都为 false。如果这不是我们想要的,那么我们最好在 descriptor 中将它们设置为 true。
设置只读属性
我们可以通过更改 writable 标志来把 user.name 设置为只读(user.name 不能被重新赋值)
let user = {
name: "coolFish"
};
Object.defineProperty(user, "name", {
writable: false
});
user.name = "Pete"; // Error: Cannot assign to read only property 'name'
现在没有人可以改变我们 user 的 name,除非它们应用自己的 defineProperty 来覆盖我们的 user 的 name。
不可枚举属性
我们向 user 添加一个自定义的 toString。对象的内置 toString 是不可枚举的,它不会显示在 for...in 中。但是如果我们添加我们自己的 toString,那么默认情况下它将显示在 for...in 中
let user = {
name: "coolFish",
toString() {
return this.name;
}
};
// 默认情况下,我们的两个属性都会被列出:
for (let key in user) alert(key); // name, toString
如果我们不喜欢它,那么我们可以设置 enumerable:false。之后它就不会出现在 for...in 循环中了,就像内建的 toString 一样,简单说,就是我们可以通过这些属性描述符,使我们模仿很多原生属性,更加灵活的使我们的业务达到预期
let user = {
name: "coolFish",
toString() {
return this.name;
}
};
Object.defineProperty(user, "toString", {
enumerable: false
});
// 现在我们的 toString 消失了:
for (let key in user) alert(key); // name
不可枚举的属性也会被 Object.keys 排除
alert(Object.keys(user)); // name
这样,我们可以控制一些方法或者变量的出现范围,更加灵活