对象属性是由名字、值和一组特性(attribute)构成。
在 javaSctipr 中,属性的值可以用一个或两个方法代替,分别是 getter 和 setter,除了这两个方法之外,属性还包含一些标识他们可写,可枚举和可配置的的特性。
ECMAScript 5 中定义了一个名为“属性描述符”(property descriptor)的对象,用这个对象代表属性的特性。 属性描述符分为两种:
- 数据属性:value(值)、writale(可写性)、enumerable(可枚举性)和 configurable(可配置性)。
- 存取性属性:getter 和 setter.
数据属性
数据属性的 4 个特性分别为它的值(value), 可写性(writable),可枚举性(enumerable)和可配置性(configurble)。 数据属性的描述符对象的属性:
value; // 值
writable; // 可写性
enumerable; // 可枚举性
configurble; // 可配置性
其中 writable、enumerable 和 configurble 都是布尔值。
value(值)
var obj = {}; // 定义一个对象
Object.defineProperty(obj, 'name', {
value: 'Zaoei'
}); // 设置一个name属性,并设置值
obj.name; // Zaoei
writable(可写性)
var obj = {}; // 定义一个对象
Object.defineProperty(obj, 'name', {
value: 'Zaoei'
}); // 设置一个name属性,并设置值,并具有可写性
console.log(obj.name); // Zaoei
obj.name = 1; // 改变值
console.log(obj.name); // 1
Object.defineProperty(obj, 'name', {
writable: false
}); // 把name属性的可写性设置为false
obj.name = 'Zaoei'; // 改变值,由于设置了可写性为false,虽然不报错,但是值未改变 。
console.log(obj.name); // 1 ,值不变
enumerable(可枚举性)
var obj = {}; // 定义一个对象
Object.defineProperty(obj, 'name', {
value: 'Zaoei',
enumerable: true
}); // 设置一个name属性,并设置值,并具有可枚举性
console.log(Object.keys(obj)); // ["name"]
Object.defineProperty(obj, 'name', {
enumerable: false
}); // 把name属性的可枚举性设置为false
console.log(Object.keys(obj)); // []
for (var key in obj) {
console.log(key);
} // 使用for循环也遍历不到name属性
configurable(可配置性)
var o = {};
Object.defineProperty(o, 'age', {
value: 18,
writable: true,
enumerable: true,
configurable: false
}); // 设置可配置性为false
o.age = 1; // 修改值
console.log(o.age); // 1,修改成功
console.log(Object.keys(o)); // ["age"] 枚举成功
delete o.age; // 删除age属性
console.log(o); // {age:1} 删除属性失败
Object.defineProperty(o, 'age', {
value: 1000,
writable: false,
enumerable: false,
configurable: true
}); // 设置对象的特性,直接报错
可以看到一旦对属性的可配置性设置为 false,就不能对这个属性特性进行任何的修改,详细规则请看最下。
存取器属性
由 getter 和 setter 定义的属性称为“存取器属性”,它们都是函数值。存取器属性的描述符对象则用 get 和 set 属性代替 value 和 writable。
getter
当程序查询存取器的值时,JavaScript 调用 getter 方法(无参数),这个方法返回的值,就是属性存取表达式返回的值。
var obj = {};
Object.defineProperty(obj, 'name', {
get: function () {
return '张三';
}
});
console.log(obj.name); // 张三
setter
当程序设置一个存取器属性的值时,JavaScript 调用 setter 方法,将赋值表达式右侧的值当作参数传入 setter。
获取属性描述符
Object.getOwnPropertyDescriptor(obj, name)
通过调用Object.getOwnPropertyDescriptor()可以获得某个对象特点属性的属性描述符。
/*
*参数1:需要查找的目标对象
*参数2:目标对象内属性名称
*
*Object.getOwnPropertyDescriptor只能得到自由属性的描述符。
*/
Object.getOwnPropertyDescriptor(obj, 'name'); // {value: 1, writable: true, enumerable: true, configurable: true}
设置属性描述符
Object.defineprtperty()
通过调用Object.defineProperty(),传入要修改的对象、要创建或修改的属性名以及属性描述符对象。
/*
*参数1:要定义属性的对象。
*参数2:要定义或修改的属性的名称或 Symbol 。
*参数3:要定义或修改的属性描述符。
*
*属性描述符的的默认值不是undefined就是false.
*/
Object.defineProperty(obj, 'attributeName', {
value: undefined,
writable: false,
enumerable: false,
conficgurable: false
});
Object.definePorperties(obj, props)
通过使用 Object.defineProperties()方法,同时修改或创建多个属性。
/*
*参数1:在其上定义或修改属性的对象。
*参数2:要定义其可枚举属性或修改的属性描述符的对象。
*/
Object.defineProperties(obj, {
attrName1: { value: '张三', writable: true, enumerable: true, configurable: true },
attrName2: { value: '李四', writable: true, enumerable: true, configurable: true }
});
规则
Object.definePorperty()和 Object.defineProperties()的详细规则,不符合则直接报错。
- 如果对象是不可拓展的,则可以编辑已有的自有属性,但不能给它添加新属性;
- 如果属性是不可配置的,则不能修改它的可配置性和可枚举性;
- 如果存取器属性是不可配置的,则不能修改其 getter 和 setter 方法,也不能将它转换为数据属性;
- 如果数据属性是不可配置的,则不能将它转换成存取器属性;
- 如果数据属性是不可配置的,则不能将它的可写性从 false 修改为 true,但可以从 true 修改为 false;
- 如果数据属性是不可配置且不可写的,则不能修改它的值。
- 如果属性是可以配置,但不可写的,属性的值是可以调用方法 Object.defineProperty 和 Object.defineProperties()修改的(实际上是先将它标记为可写的,然后修改他的值,最后转换为不可写的)
资料参考
《JavaScript 权威指南》 MDN web 文档