在JavaScript开发中,遍历对象属性是最基础却最容易混淆的操作之一。不同的遍历方法会返回不同的结果集,理解它们的细微差别对于编写可靠的代码至关重要。本文将带你彻底掌握5种主流对象遍历方式,并通过直观的打印示例展示它们的实际行为差异。
javascript复制const obj = { a: 1, b: 2, [Symbol('c')]: 3 }
for (let key in obj) {
console.log(key) // 输出: 'a', 'b'
}
实际开发中建议始终配合hasOwnProperty使用:
javascript复制for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 处理逻辑
}
}
javascript复制function Parent() { this.parentProp = 1 }
Parent.prototype.protoProp = 2
const child = new Parent()
child.childProp = 3
console.log(Object.keys(child)) // ['parentProp', 'childProp']
javascript复制const obj = { a: 1, b: 2, c: 3 }
console.log(Object.values(obj)) // [1, 2, 3]
javascript复制const config = { host: 'example.com', port: 8080 }
for (const [key, value] of Object.entries(config)) {
console.log(`${key}: ${value}`)
}
// 输出:
// host: example.com
// port: 8080
javascript复制const obj = {}
Object.defineProperties(obj, {
a: { value: 1, enumerable: true },
b: { value: 2, enumerable: false }
})
console.log(Object.getOwnPropertyNames(obj)) // ['a', 'b']
| 方法 | 包含原型链 | 包含不可枚举 | 包含Symbol | 返回类型 |
|---|---|---|---|---|
| for...in | 是 | 否 | 否 | 迭代 |
| Object.keys() | 否 | 否 | 否 | Array |
| Object.values() | 否 | 否 | 否 | Array |
| Object.entries() | 否 | 否 | 否 | Array |
| Object.getOwnPropertyNames() | 否 | 是 | 否 | Array |
只需要键名时:
需要键值对时:
new Map(Object.entries(obj))完整属性检查:
对大型对象:
const keys = Object.keys(obj)高频操作场景:
问题1:遍历时出现意外属性
javascript复制// 原型污染示例
Object.prototype.extraProp = 'test'
const obj = { a: 1 }
for (let key in obj) {
console.log(key) // 输出 'a' 和 'extraProp'
}
解决方案:
问题2:修改对象属性导致遍历异常
javascript复制const obj = { a: 1, b: 2 }
Object.defineProperty(obj, 'a', { enumerable: false })
console.log(Object.keys(obj)) // 只输出 ['b']
最佳实践:
javascript复制const obj = {
[Symbol('id')]: 123,
name: 'test'
}
console.log(Reflect.ownKeys(obj))
// 输出: ['name', Symbol(id)]
javascript复制const handler = {
ownKeys(target) {
return [...Reflect.ownKeys(target), 'extraKey']
}
}
const proxy = new Proxy({ a: 1 }, handler)
console.log(Object.keys(proxy)) // ['a', 'extraKey']
在实际项目中,我通常会根据以下原则选择遍历方法:
对于日常开发,Object.keys()和Object.entries()能满足80%的场景,它们提供了最安全可控的遍历方式。而在编写工具函数或库时,则需要更全面地考虑各种边界情况。