JavaScript对象属性

JavaScript对象与原型体系中我们提到过, 对象具有状态和行为的特征。

在其他编程语言中,对象状态和行为分别被抽象成了属性和方法,而JavaScript在自己的对象模型设计中将它们都抽象成了对象的属性

高度的抽象也使得关于对象的属性设计上明显比Java等其他语言更为复杂, 本文主要对JavaScript的属性的特点以及操作他们的函数进行了梳理和总结。

JavaScript对象的属性主要可以分为数据属性访问器属性两类,同时,对象所具有的属性并非简单的K-V键值对, 每个属性都由一组特征(attribute)来描述。

数据属性

数据属性是我们通常使用的K-V键值对,它主要有四个特征来描述:

  • value 属性的数据值, 默认值为undefined
  • enumerable 表示该属性是否可枚举
  • configurable 表示该属性是否能被删除,或特征值被修改
  • writable 表示该属性值是否能修改

访问器属性

访问器属性定义了在访问对象属性时的行为,它同样有四个特征来描述:

  • get 读取属性时调用的函数, 默认值为undefined
  • set 设置属性时访问的函数, 默认值为undefined
  • enumerable 表示该属性是否可枚举
  • configurable 表示该属性是否能被删除,或特征值被修改

定义和修改属性的特征

在日常开发过程中,我们通常会直接为某个对象的属性赋值:

var obj={
  aaa:"bbb"
  get bbb(){
    return "aaa"
  }
}

通过这种方式所产生的数据属性特征{enumerable, configurable, writable} 都默认为true.

我们还可以使用Object.defineProperty函数定义或修改对象的数据属性或者访问器属性。

这里需要注意的一点是, 通过Object.defineProperty函数所定义的属性,如果没有显式指定相应的特征值, 则{enumerable, configurable, writable} 都默认取值为false.

通过Object.getOwnPropertyDescriptor函数, 可以读取指定对象上自身属性的属性特征(属性特征描述符), 改方法返回了一个关于属性特征的Descriptor对象:

{
  value,
  enumerable,
  configurable,
  writable,
  get,
  set
}

通过Descriptor可以访问到指定属性的特征值。

属性的configurable特征通常表示该属性本身是否能够被删除或被修改, 一旦设置为false则无法改为true。 同时,当configurable为false的时候, 除了能修改writable之外的特征值都会报错。

总结

通过上面的介绍,我们可以看到,JavaScript对象模型其实是一个Map结构:<propName:Descriptor>, key是属性名,而value则是该属性的Descriptor对象。

这样的设计让JavaScript的对象属性具有了强大的动态性,可以在运行时灵活地修改一个对象的属性。