在 JavaScript 中,for…in、Object.keys() 和 Reflect.ownKeys() 是三种常用来遍历对象属性的方法,但它们的行为和适用场景各不相同。下面简述下它们的工作原理、适用场景以及各自的区别。

for…in

概念:for…in用于遍历对象的可枚举属性,不仅遍历对象自身的属性,也会遍历其原型链上的可枚举属性。

特点:

  • 遍历对象自身和继承的可枚举属性
  • 只会遍历可枚举的属性(enumerable: true)。

缺点:

  • 如果对象继承了原型链上的属性,且这些属性是可枚举的,for…in 也会遍历这些属性,可能导致意外行为。若只想遍历对象自身的属性,需要配合 hasOwnProperty() 来过滤掉继承的属性
const obj = { a: 1, b: 2 }
Object.getPrototypeOf(obj).c = 3
 
for (let key in obj) {
  console.log(key) // 输出: "a", "b", "c"(包括继承的 c)
}
 
for (let key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(key) // 仅输出 "a", "b"
  }
}
 

Object.keys()

概念:Object.keys() 返回对象自身的可枚举属性组成的数组,不包括原型链上的属性。

特点:

  • 仅返回对象自身的可枚举属性(不会遍历原型链上的属性)。
  • 返回结果是一个数组,数组中的每一项是对象的属性名称。

Reflect.ownKeys()

概念:Reflect.ownKeys() 返回对象的所有自身属性,包括可枚举和不可枚举的属性,且会返回符号(Symbol)属性。

特点:

  • 返回对象自身的所有属性,无论它们是否可枚举。
  • 能够遍历符号属性(Symbol)。

优点:

  • 完整遍历对象自身的属性,包含不可枚举和 Symbol 属性,适用于高级场景。

缺点:

  • 由于它返回所有属性,包括不可枚举的属性,可能会产生不必要的结果,需要仔细处理。

总结

选择建议:

  • for…in:适合需要遍历所有可枚举属性(包括继承的属性)的场景。
  • Object.keys():适合只需要遍历对象自身可枚举属性的场景,使用频率较高。
  • Reflect.ownKeys():适合需要完整获取对象自身属性(包括不可枚举和符号属性)的高级用法。