2分钟轻松搞定Object.keys(),for...in,getOwnPropertyNames()的区别

1,552 阅读2分钟

之前总是搞不清Object.keys(),for...in,getOwnPropertyNames()这三者的关系,现在统一总结出来,方便记忆。

一、先看这三者的定义

  • for...in : 以任意顺序遍历一个对象的可枚举属性,以及对象从其构造函数原型中继承的属性(object.prototype)。对于每个不同的属性,语句都会被执行。
    注:如果不想遍历object.prototype的属性,可以使用hasOwnProperty

  • Object.keys(object) : 会返回一个由一个给定对象的自身 可枚举属性 组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致 。(相当for...in使用hasOwnProperty)

  • Object.getOwnPropertyNames(object) : 方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。

二、具体用法

所有用法都基于该例子

// 创建一个构造函数Person
function Person () {
  
}
// 给构造函数的原型对象创建两个属性,name,sayName
Person.prototype.name = 'mzong'
Person.prototype.sayName = function () {
  console.log(this.name)
}

// 创建一个实例p1,给p1实例添加两个属性,work,eatting
var p1 = new Person()
p1.work = 'work'
p1.eatting = 'food'

1. for...in

for (var props in p1) {
  console.log('for-in:: '+props)
}

// 结果
// for-in:: work
// for-in:: eatting
// for-in:: name  该属性继承于Person.prototype
// for-in:: sayName  该属性继承于Person.prototype
// 从结果可以看出,for...in不但循环自己属性,还会循环构造函数都prototype中都属性。

// 如果实例属性是不可枚举的话,那for...in能循环出来吗?
// 我们把p1的work属性设为不可枚举
Object.defineProperty(p1, 'work', {
  enumerable: false // 默认为true,表示可枚举
})

// 继续循环
for (var props in p1) {
  console.log('for-in:: '+props)
}
// 结果
// for-in:: eatting
// for-in:: name  该属性继承于Person.prototype
// for-in:: sayName  该属性继承于Person.prototype
// 看吧,work没被循环出来,因为是不可枚举的。


// 如果想要循环p1实例自己的属性,则使用hasOwnProperty即可。
for (var props in p1) {
  if (p1.hasOwnProperty(props)) {
    console.log('for-in:: '+props)
  }
}
// 结果
// for-in:: work
// for-in:: eatting
// 从结果可以看出,如果实例p1只想要循环自己的属性,则使用hasOwnProperty即可。

2. Object.keys()

console.log(Object.keys(p1))
// 结果:["work", "eatting"]
// 得到是一个可枚举属性数据,只循环实例p1自身属性,不循构造函数的prototype。
// 可见Object.keys()相当于for...in使用hasOwnProperty。

// 同样的,如果work是不可枚举的,那Object.keys()能循环出来吗?
// 我们把p1的work属性设为不可枚举
Object.defineProperty(p1, 'work', {
  enumerable: false // 默认为true,表示可枚举
})
console.log(Object.keys(p1))
// 结果:["eatting"]
// 看吧,work没被循环出来,因为是不可枚举的。

3. Object.getOwnPropertyNames()

Object.keys(Person.prototype)
// 结果
// ["name", "sayName"]

Object.getOwnPropertyNames(Person.prototype)
// 结果
// ["constructor", "name", "sayName"]
// 看吧,把constructor这个不可枚举的属性也循环出来啦。

总结

总结:在for...in循环当中,为了不去循环到构造函数的prototype中的属性,我们常用hasOwnProperty来过滤。而有了Object.keys()和getOwnPropertyNames之后,就可以代替for...in啦。