Javascript面向对象(一)——属性标志与描述
我们都知道,对象可以存储属性。属性一般都是简单的键值对,但一个对象属性可以更复杂、优美。
属性标志
writable
– 如果为true
, 属性可以改变,否则为只读。enumerable
– 如果为true
, 属性可以在loop…in中被列出,否则不被列出。configurable
– 如果为true
, 属性可以被删除或修改,否则不行。
这些属性通常很少使用,使用常规方式创建对象,他们的值都为true
,但可以随时改变他们。
首先,看看如何获取他们的值。方法Object.getOwnPropertyDescriptor
允许我们查询属性的完整信息。
let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
其返回值一般称为“属性描述对象”,其包含属性值和所有标志。示例如下:
let user = {
name: "John"
};
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/* property descriptor:
{
"value": "John",
"writable": true,
"enumerable": true,
"configurable": true
}
*/
改变标志,可以使用Object.defineProperty
,语法如下:
Object.defineProperty(obj, propertyName, descriptor)
如果属性已经存在,则更新标识,否则使用给定的值和属性标识创建。注意:如果没有提供标识,默认为false
。
示例,这里属性name
被创建,所有标识为false
。
let user = {};
Object.defineProperty(user, "name", {
value: "John"
});
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": "John",
"writable": false,
"enumerable": false,
"configurable": false
}
*/
和正常方式创建对象相比,所有标识为false
,如果没有特殊需要,我们最好设置其为true
。下面详述每个属性标识。
只读
我们使user.name
只读,通过改变writable
标识:
let user = {
name: "John"
};
Object.defineProperty(user, "name", {
writable: false
});
user.name = "Pete"; // Error: Cannot assign to read only property 'name'...
现在我们不能修改user对象的name属性值,除非我们使用defineProperty
方法覆盖标识。
下面示例效果一样,但对象的属性事前不存在。
let user = { };
Object.defineProperty(user, "name", {
value: "Pete",
// for new properties need to explicitly list what's true
enumerable: true,
configurable: true
});
alert(user.name); // Pete
user.name = "Alice"; // Error
非枚举
现在我们user
对象增加自定义toString
方法。
通常,对象内置的toString
方法是非枚举的,使用for..in
不会显示,但是如果增加toString
方法,则可以通过for..in
列出。如果我们不希望被列出,可以使用enumerable:false
.则不会被列出,和内置的一样。
let user = {
name: "John",
toString() {
return this.name;
}
};
// By default, both our properties are listed:
for(let key in user) alert(key); // name, toString
Object.defineProperty(user, "toString", {
enumerable: false
});
// Now toString disappears:
for(let key in user) alert(key); // name
非枚举属性通过Object.keys
方法通用也不能被枚举。
非配置
非配置标识(configurable:false
)通常设置在内置对象属性中使用。
非配置标识不能通过defineProperty
方法修改或删除。
示例:Math.PI
同时是只读、非枚举、非配置:
let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": 3.141592653589793,
"writable": false,
"enumerable": false,
"configurable": false
}
*/
所以,开发者不能改变或覆盖他们。
Math.PI = 3; // Error
// delete Math.PI won't work either
使属性为非配置,是单向的,不能改回来。因为defineProperty
方法在非配置属性上不工作。
这里我们使user.name
用于密封。
let user = { };
Object.defineProperty(user, "name", {
value: "John",
writable: false,
configurable: false
});
// won't be able to change user.name or its flags
// all this won't work:
// user.name = "Pete"
// delete user.name
// defineProperty(user, "name", ...)
Object.defineProperty(user, "name", {writable: true}); // Error
使用严格模式出现错误
在非严格模式下,修改只读属性不会报错。但属性不会改变。强制修改标志在非严格模式下被安静地忽略。
Object.defineProperties
方法Object.defineProperties(obj,descriptors)
允许一次定义多个属性。语法如下:
Object.defineProperties(obj, {
prop1: descriptor1,
prop2: descriptor2
// ...
});
示例:
Object.defineProperties(user, {
name: { value: "John", writable: false },
surname: { value: "Smith", writable: false },
// ...
});
Object.getOwnPropertyDescriptors
使用方法Object.getOwnPropertyDescriptors(obj)
方法可以一次性获取多个描述。
和Object.defineProperties
一起使用,他能够使用“标识感知”的方式克隆对象:
let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));
通常我们克隆对象,使用拷贝属性赋值,代码如下:
for(let key in user) {
clone[key] = user[key]
}
但是,这样并没有拷贝属性,因此要完全克隆,在克隆之前使用Object.defineProperties
方法。
全局密封对象
属性描述在在单个属性级别上起作用。也有一些方法实现限制整个对象。
Object.preventExtensions(obj)
禁止给对象增加属性
Object.seal(obj)
禁止增加/删除属性,设置所有存在属性的configurable为false。
Object.freeze(obj)
禁止增加/删除属性,设置所有存在属性的configurable:false, writable: false.
一些测试方法如下:
Object.isExtensible(obj)
Returns false if adding properties is forbidden, otherwise true.
Object.isSealed(obj)
Returns true if adding/removing properties is forbidden, and all existing properties have configurable: false.
Object.isFrozen(obj)
Returns true if adding/removing/changing properties is forbidden, and all current properties are configurable: false, writable: false.
这写方法实际情况很少使用。
本文参考链接:https://blog.csdn.net/neweastsun/article/details/69055998