之前总是搞不清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啦。