问题来源:Object.defineProperty和普通的赋值操作有什么区别?我们都知道像有些操作是会遍历原型链的,但是Object上其实有很多方法和属性,在遍历的时候并没有将其遍历出来,但是他们却是可用的,这里引出概念"可读不可写"


要注意的属性名:

一个对象的属性名可以是任何有效的 JavaScript 字符串,或者可以被转换为字符串的任何类型,包括空字符串。然而,一个属性的名称如果不是一个有效的 JavaScript 标识符(例如,一个由空格或连字符,或者以数字开头的属性名),就只能通过方括号标记访问。这个标记法在属性名称是动态判定(属性名只有到运行时才能判定)时非常有用。


枚举对象的属性:

  1. for...in:包括链的,访问包括原型链的可枚举属性
  2. Object.keys(obj):只访问自身的,访问不包括原型链的可枚举属性
  3. Object.getOwnPropertyNames(obj): 访问自身的不论枚举与否,自身包含的所有属性(不包括原型中)(无论是否可枚举)

默认情况下,使用 Object.defineProperty() 添加的属性值是不可修改(immutable)的。

对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符

共享以下可选键值(默认值是指在使用 Object.defineProperty() 定义属性时的默认值):

  • configurable
    true 时,才能够被改变。 默认为 false。

  • enumerable
    true 时,该属性才会出现在对象的枚举属性中。 默认为 false。

数据描述符


可选键值:

  • value
    可以是任何有效的 JavaScript 值(数值,对象,函数等)。 默认为 undefined。
  • writable
    true 时,上面的 value,才能被赋值运算符 (en-US)改变。 默认为 false。

存取描述符


即 getter 函数+ setter 函数。

可选键值:

  • get
    该函数的返回值会被用作属性的值。 默认为 undefined。
  • set
    当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。 默认为 undefined。

alt

直接赋值和使用Object.defineProperty()的默认值不同

直接赋值:

o.a = 1;
// 等同于:
Object.defineProperty(o, "a", {
  value: 1,
  writable: true,
  configurable: true,
  enumerable: true
});

Object.defineProperty():

Object.defineProperty(o, "a", { value : 1 });
// 等同于:
Object.defineProperty(o, "a", {
  value: 1,
  writable: false,
  configurable: false,
  enumerable: false
});

configurable 特性表示对象的属性是否可以被删除,以及除 value 和 writable 特性外的其他特性是否可以被修改。

这里的很多属性,如在configrable和numerable,非严格模式下不会报错。

还可以通过Object.defineProperty给原型上加属性。

function myclass() {
}

Object.defineProperty(myclass.prototype, "x", {
  get() {
    return this.value;
  },
  set(x) {
    this.value = x;
  }
});