Skip to main content

属性特性

· 7 min read
赵炜

对象属性是由名字、值和一组特性(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 文档