获取对象的属性值

写在前面

ECMAScript中,经过key获取Objectvalue是再日常不过的操做。但是,因为原型链(prototype chain)、类继承(class extend)的存在,在你遍历对象属性的时候,你想要/不想要获取原型链上,或者父类的属性,结果都会不如你的预期。还有一种状况,你要取到Symbol的属性,却没法取得。javascript

本片文章将会对比几种遍历对象属性的方法,让你能够准确的获取到对象上的值。vue

方法对比

咱们先使用构造函数建立一个对象,在构造函数中设置其实例属性,而后设置构造函数原型对象的属性,而后再给实例添加属性。java

// 构造函数
function MakeObj () {
  Object.defineProperties(this, {
    x1: {
      value: 1,
      enumerable: true
    },
    x2: {
      value: 11,
      enumerable: false
    }
  })
}
// 原型对象
Object.defineProperties(MakeObj.prototype, {
  y1: {
    value: 2,
    enumerable: true
  },
  y2: {
    value: 22,
    enumerable: false
  }
})

// 建立实例
var obj = new MakeObj()

// 设置实例对象属性
Object.defineProperties(obj, {
  z1: {
    value: 3,
    enumerable: true
  },
  z2: {
    value: 33,
    enumerable: false
  }
})
复制代码

咱们对比一下Object.keysObject.getOwnPropertyNamesfor...infor...of框架

Object.keys(obj) // ["x1", "z1"]
Object.getOwnPropertyNames(obj) // ["x1", "x2", "z1", "z2"]

var forIn = []
for (let x in obj) {
  forIn.push(x)
}
forIn // ["x1", "z1", "y1"]

var forOf = []
for (let x in obj) {
  forOf.push(x)
}
forOf // ["x1", "z1", "y1"]
复制代码

用表格看更清晰:函数

方法 实例属性 原型对象属性
可枚举(x1,z1) 不可枚举(x2,z2) 可枚举(y1) 不可枚举(y2)
Object.keys × × ×
Object.getOwnPropertyNames × ×
for...in × ×
for...of × ×


因此,若是你想要:ui

  • 仅遍历可枚举的实例属性,使用Object.keys
  • 遍历包括枚举和不可枚举的实例属性,使用Object.getOwnPropertyNames
  • 若是你要遍历包括可枚举的实例属性和原型对象上的可枚举属性,使用for...infor...of

获取Symbol属性值

若是咱们设置了Symbol属性呢?this

var sml = Symbol('key')
var obj = {
 x: 1,
 [sml]: 'symbol value'
}

var forIn = []
for (let x in obj) {
  forIn.push(x)
}

var forOf = []
for (let x in obj) {
  forOf.push(x)
}

Object.keys(obj).includes(sml) // false
Object.getOwnPropertyNames(obj).includes(sml) // false
forIn.includes(sml) // false
forOf.includes(sml) // false

Object.getOwnPropertySymbols(obj).includes(sml) // true
复制代码

咱们看到上面提到的几个方法都是没法获取到 Symbol值的。因此, ECMAScript提供了Object.getOwnPropertySymbols方法来遍历实例属性是Symbol的对象。
咱们继续看一下这个方法对不可枚举属性以及原型对象属性的遍历:spa

var ctor = function() {}
var makeSml = key => Symbol(key)
// 原型对象
Object.defineProperties(ctor.prototype, {
  [makeSml('y1')]: {
    value: 2,
    enumerable: true
  },
  [makeSml('y2')]: {
    value: 22,
    enumerable: false
  }
})
var obj = new ctor()

// 设置实例对象属性
Object.defineProperties(obj, {
  [makeSml('z1')]: {
    value: 3,
    enumerable: true
  },
  [makeSml('z2')]: {
    value: 33,
    enumerable: false
  }
})

Object.getOwnPropertySymbols(obj) // [Symbol(z1), Symbol(z2)]
复制代码

咱们仍是用表格展现一下:prototype

方法 实例属性 原型对象属性
可枚举(z1) 不可枚举(z2) 可枚举(y1) 不可枚举(y2)
Object.getOwnPropertySymbols × ×


因此, Object.getOwnPropertySymbols仅能够获取到实例属性为 Symbol的属性值。
设计

总结

因为 ECMAScript版本不断更新发布,这门语言会在兼容一下老的设计和新的设计中变得愈来愈复杂、臃肿。简单的一个获取对象属性值,却提供了好几个方法。而且,有时候你还要组合使用它们才能达到你的需求,好比你要获取一个对象的全部实例属性值,不管普通仍是 symbol,那么你可能就要组合使用 Object.getOwnPropertyNamesObject.getOwnPropertySymbols,若是你只取可枚举的普通实例属性值,那么你还要取Object.getOwnPropertyNamesObject.keys的交集。

在通常的业务场景中,咱们可能用不到这些方法,不少时候,一个Object.keys就能知足需求。但在构建一些基础库(例如 lodash),或者框架的时候(例如 vue)时,咱们必须考虑到这些。

参考

  1. Object.keys
  2. Object.getOwnPropertyNames
  3. for...in
  4. for...of
相关文章
相关标签/搜索