for ... in、Object.keys 和 Object.getOwnPropertyNames 的区别

Last Modified: 2022/12/28

for...in

for...in 语句以任意顺序迭代一个对象的除 Symbol 以外的可枚举属性,包括继承的可枚举属性

let point = {x: 1, y: 2}
for (var prop in point) {
    console.log('property:', prop, ',value:', point[prop])
}

运行程序控制台输出如下:

property: x ,value: 1
property: y ,value: 2

可以看出 point 对象的属性 x 和 y 都被正常遍历输出,现在我们通过 Object.defineProperty 将 x 属性修改为不可枚举,然后再次遍历 point:

// 将 x 改为不可枚举
Object.defineProperty(point, 'x', {
    enumerable: false
})
for (var prop in point) {
    console.log('property:', prop, ',value:', point[prop])
}

由于 point 对象的 x 属性不可遍历,因此程序输出如下:

property: y ,value: 2

上面提到了 for... in 除了遍历自身可枚举的属性之外还会遍历继承的(即原型链上的)可枚举的属性,下面我们试一下继承:

let parent = {p: 1}
let point = {x: 1, y: 2}
// 让 point 对象继承 parent 对象,继承的方式有多种,这里为了演示方便使用了 __proto__ 实现继承
point.__proto__ = parent
for (var prop in point) {
    console.log('property:', prop, ',value:', point[prop])
}

运行程序控制台输出如下:

property: x ,value: 1
property: y ,value: 2
property: p ,value: 1

由于 point 继承了 parent 对象,因此使用 for...in 遍历也会输出 parent 对象中可枚举的属性。

Object.keys

Object.keys 遍历对象自身可枚举的属性,不包括继承的属性

let a = ['a', 'b', 'c']
console.log(Object.keys(a)) // 输出:['0', '1', '2']

以上用数组演示 Object.keys 的用法,可以看出数组的属性为数组下标,实际上可以将数组 a 看成 {0: 'a', 1: 'b', 2: 'c'}

Object.getOwnPropertyNames

Object.getOwnPropertyNames 遍历对象自身的属性(包括不可枚举的属性),不包括继承的属性

let a = ['a', 'b', 'c']
console.log(Object.getOwnPropertyNames(a)) // 输出:['0', '1', '2', 'length']

比较本例的输出和上一个例子的输出,不难看出本例的输出多了一个 length 属性。这是由于数组的 length 属性是不可枚举的,因此 Object.keys 不会输出 length 属性。

总结

  • for...in 语句以任意顺序迭代一个对象的除 Symbol 以外的可枚举属性,包括继承的可枚举属性。
  • Object.keys 遍历对象自身可枚举的属性,不包括继承的属性。
  • Object.getOwnPropertyNames 遍历对象自身的属性,包括不可枚举的属性,不包括继承的属性。

注意事项

不建议使用 for...in 遍历数组,我们可以使用 for...of 或者 Array.prototype.forEach 遍历数组。

有问题吗?点此反馈!

温馨提示:反馈需要登录