前言
js里面遍历一个对象的属性有很多种方式,比如:Object.keys 、for...in、Object.getOwnPropertyNames等等,平时写业务代码的时候,大家随便用哪个。
可是它们之间的区别,我相信,大部分(不是所有,此处狗头🐶保命)前端小伙伴应该都不太清楚
属性的可枚举性
可枚举属性
通常我们给对象定义、或者新增一个属性的方式基本如下
let obj = { a: 1 }
obj.b = 2
上面代码给obj对象添加了a、b两个属性,这两个属性都是可枚举的
不可枚举属性
那么怎么让添加的属性不可枚举呢,见如下代码
Object.defineProperty(obj,'c',{
enumerable: false,
value: 3
})
上面代码,又给obj添加了一个c属性,此时c属性就是不可枚举的。关键就是enumerable: false这句代码,如果不特别给enumerable赋值成false,那么默认都是可枚举的
如何判断
判断对象中的某个属性是否可枚举,js有提供原生的propertyIsEnumerable方法
obj.propertyIsEnumerable('a') // true
obj.propertyIsEnumerable('b') // true
obj.propertyIsEnumerable('c') // false
上面代码执行的结果符合预期,只有c是不可枚举的
原型链属性
有的属性不是直接存在于对象中,而是存在于对象的原型链中
添加原型链属性
Object.prototype.d = 4
上面代码,给Object的原型链添加了一个属性d。此时d没有直接存在于obj中,而是存在于obj的原型链上
如何判断
in
通常我们会直接用in来判断某个属性是不是存在某个对象中
'a' in obj // true
'b' in obj // true
'c' in obj // true
'd' in obj // true
上面结果表明in操作符会检查属性是否在对象以及其原型链中
hasOwnProperty
hasOwnProperty也可以来判断属性是否在对象中
obj.hasOwnProperty('a') // true
obj.hasOwnProperty('b') // true
obj.hasOwnProperty('c') // true
obj.hasOwnProperty('d') // false
和in对比一下,大家可以看出差别,obj.hasOwnProperty('d')的结果是false,而d是添加在原型链中的属性,所以hasOwnProperty只会检查属性是否在对象本身,而不会去检查是否在原型链中
两者结合
所以结合in和hasOwnProperty我们就可以知道某个属性是直接在对象中,还是在对象的原型链中
'd' in obj && !obj.hasOwnProperty('d') // true (属性在原型链中)
对象遍历
通过上面的介绍,大家应该也猜测到,Object.keys 、for...in、Object.getOwnPropertyNames的区别其实就在于能否遍历对象的可枚举属性,以及能否遍历原型链上的属性
for...in
首先说下for...in,执行如下代码
for(let key in obj){
console.log(key)
}
// a
// b
// d
打印出了a、b、d三个属性,c没有打印出来,所以for...in只会遍历对象本身的、以及原型链上的所有可枚举属性
Object.keys
执行如下代码
Object.keys(obj)
// ["a", "b"]
打印出了a、b两个属性,c、d没有打印出来,所以Object.keys只会遍历对象本身的可枚举属性,不会遍历原型链上的属性
Object.getOwnPropertyNames
执行如下代码
Object.getOwnPropertyNames(obj)
// ["a", "b", "c"]
打印出了a、b、c三个属性,没有打印出d,所以Object.getOwnPropertyNames只会遍历对象本身的所有属性,包括不可枚举属性,不会遍历原型链上的属性
总结
上面的内容是我看 《你不知道Javascript(上卷)》 第三章对象遍历 部分总结出来的东西,如有疑问,欢迎在评论区留言