JavaScript 对象的属性描述符

本文主要学习一下 JavaScript 中对象的属性描述符。

从 ES5 开始,所有的属性都具备了属性描述符。下面是查看和配置属性描述符的方式:

var obj = {
  a: ''
}

Object.getOwnPropertyDescriptor(obj, 'a');

// {
//   configurable: true,
//   enumerable: true,
//   value: "",
//   writable: true
// }

Object.defineProperty(obj, 'b', {
  configurable: true,
  enumerable: true,
  value: "",
  writable: true
})

// { a: '', b: '123'}

属性描述一共四个属性,分别来认识一下:

configurable

只要属性的 configurable 是 true,就可以使用 defineProperty(..) 方法来修改属性描述符。

var myObject = {
  a: 2
};
myObject.a = 3;
myObject.a; // 3

Object.defineProperty(myObject, "a", {
  value: 4,
  writable: true,
  configurable: false, // 不可配置!
  enumerable: true
});

myObject.a; // 4
myObject.a = 5;
myObject.a; // 5

Object.defineProperty(myObject, "a", {
  value: 6,
  writable: true,
  configurable: true,
  enumerable: true
}); // TypeError

delete myObject.a;
myObject.a // 5

可以看到,将 configurable 设为 false 后将无法再次使用 Object. defineProperty () 配置,会报 TypeError 异常,所以这个行为是不可逆的。
而且也无法使用 delete 删除 configurable 为 false 的对象属性。

enumerable

这个描述符控制的是属性是否会出现在对象的属性枚举中,如 for...in... 循环。

var myObject = {
  a: 2,
  b: 3,
  c: 7,
  d: 12
};

Object.defineProperty(myObject, "e", {
  value: 4,
  writable: true,
  configurable: true, 
  enumerable: false // 不可枚举!
});

for (var key in myObject) {
  console.log(key)
}

// a
// b
// c
// d

myObject.e // 4

上面代码中,e 属性可以直接访问,但是并没有出现在 for...in 遍历中。

value

value 就是对象属性的值,这点很容易理解。

var myObject = {
  a: 2
};

Object.getOwnPropertyDescriptor(myObject, 'a');
// {
//   value: 2,
//   writable: true,
//   configurable: true,
//   enumerable: true
// }

console.log(myObject.a) // 2

Object.defineProperty(myObject, "a", {
  value: 4,
  writable: true,
  configurable: true,
  enumerable: true
});

console.log(myObject.a) // 4

writable

writable 决定了是否可以修改属性的值。

var myObject = {};
Object.defineProperty(myObject, "a", {
  value: 2,
  writable: false, // 不可写! 
  configurable: true,
  enumerable: true
});
myObject.a = 3;
myObject.a; // 2

上面代码中,无法对属性 a 的值进行修改。

不变性

说完了属性描述符,顺便说下对象属性的不变性。

1. 对象常量

通过属性描述符 writable 和 configurable 可以创建一个不可修改、重定义和删除的常量属性。

var myObject = {};
Object.defineProperty(myObject, "FAVORITE_NUMBER", {
  value: 42,
  writable: false,
  configurable: false
});

myObject.FAVORITE_NUMBER = 33 // 无效
delete myObject.FAVORITE_NUMBER // 无效
Object.defineProperty(myObject, "FAVORITE_NUMBER", {
  value: 33
}); // TypeError

2. 静止扩展

禁止对象添加新属性(不可扩展),可以使用 Object.preventExtensions(...) 方法。

var myObject = {
  a: 2
};
Object.preventExtensions(myObject);
myObject.b = 3;
myObject['c'] = 77

myObject.b; // undefined
myObject.c; // undefined

myObject.a = 3
myObject // { a: 3 }

delete myObject.a
myObject // {}

这个方法只保证了对象不可扩展性新属性,已有属性可以修改也可以删除。

3. 密封

Object.seal(...) 会创建一个密封对象,等于 Object.preventExtensions(...) 加上 configurable: false 的效果。

var obj = {
  a: 1
}

Object.seal(obj)

obj.b = 3 // { a: 1 }
delete obj.a // { a: 1 }
obj.a = 7 // { a: 7 }
Object.defineProperties(obj, 'a', {
  value: 14
}) // TypeError

冻结

Object.freeze(...) 会创建一个冻结对象,它等于 Object.seal(...) 加上 writable:false 属性。

var obj = {
  a: 1
}

Object.freeze(obj)

obj.b = 3 // { a: 1 }
delete obj.a // { a: 1 }
obj.a = 7 // { a: 1 }
Object.defineProperties(obj, 'a', {
  value: 14
}) // TypeError

最后

明天一起来聊聊对象的 setter getter 和 proxy~

你可能感兴趣的:(JavaScript 对象的属性描述符)