defineProperty

defineProperty 是 es5 加入的一个对象方法,此方法可以在一个对象上新增一个属性或者修改现有属性,并返回这个对象。

属性描述符

defineProperty 接收三个参数,obj, prop, descriptor。obj 是想要修改的对象,prop 是想要增加或修改的属性,descriptor 是属性描述符。 属性描述符有两种,数据描述符和访问器描述符。在《javascript高级程序设计第三版》中,把他叫做属性类型。

数据描述符

这些特性是为了实现 javascript 引擎用的,因此不能通过 javascript 直接访问。

  • [[Enumerable]] 是否可以for...in...枚举
  • [[Configurable]] 是否可删除(实际作用效果我觉得大于这个定义)
  • [[Writable]] 是否可修改 Value
  • [[Value]] 属性的值
var person = {
  name:'Richard'
}
// 默认属性描述符为:Enumerable:true,Configurable:true,Writable:true,Value:'Richard'

如果使用 defineProperty 创建一个属性,那么所有特性默认是 false ,如果修改一个属性,没有写入的特性默认 true ,如果先设置了 Configurable 为 false ,那么之后所有的设置都会失效。

var person = {
  name:'Richard'
}
Object.defineProperty(person,'fullname',{
  Configurable:false
})
// 无效
Object.defineProperty(person,'fullname',{
  Configurable:true,
  Writable:false
})

想修改默认属性描述符,必须通过 Object.defineProperty

WARNING

IE8 实现了definePropery 但是只存在 DOM 中,并且只能使用访问器描述符,所以避免在 IE8 下使用。

这些特性不一定是自身属性,也有可能来自继承,所以如果想设置默认值,需要冻结 Object.prototype ,或者通过 Object.create(null) 将 proto 属性指向 null 。

访问器描述符

  • [[Configurable]]
  • [[Enumerable]]
  • [[Get]] 默认值 undefined
  • [[Set]] 默认值 undefined
var person = {
  _name: 'Richard'
}
Object.defineProperty(person,'name',{
  get: function() {
    return this._name
  },
  set: function(newV) {
    this._name = newV
  }
})
person.name = 'Kame'