属性遍历方法
JavaScript 中遍历对象属性的 5 种方法及其区别
问题
JavaScript 中有哪些遍历对象属性的方法?它们有什么区别?
解答
ES6 提供了 5 种遍历对象属性的方法:
1. for…in
遍历对象自身和继承的可枚举属性(不含 Symbol)。
const parent = { inherited: 'parent' };
const obj = Object.create(parent);
obj.name = 'test';
obj[Symbol('id')] = 123;
for (let key in obj) {
console.log(key);
}
// 输出: name, inherited(包含继承属性)
2. Object.keys()
返回对象自身可枚举属性的键名数组(不含 Symbol 和继承属性)。
const obj = { a: 1, b: 2 };
Object.defineProperty(obj, 'c', {
value: 3,
enumerable: false // 不可枚举
});
obj[Symbol('d')] = 4;
console.log(Object.keys(obj));
// 输出: ['a', 'b']
3. Object.getOwnPropertyNames()
返回对象自身所有属性的键名数组(包含不可枚举,不含 Symbol)。
const obj = { a: 1 };
Object.defineProperty(obj, 'b', {
value: 2,
enumerable: false
});
obj[Symbol('c')] = 3;
console.log(Object.getOwnPropertyNames(obj));
// 输出: ['a', 'b'](包含不可枚举的 b)
4. Object.getOwnPropertySymbols()
返回对象自身所有 Symbol 属性的键名数组。
const sym1 = Symbol('x');
const sym2 = Symbol('y');
const obj = {
a: 1,
[sym1]: 2,
[sym2]: 3
};
console.log(Object.getOwnPropertySymbols(obj));
// 输出: [Symbol(x), Symbol(y)]
5. Reflect.ownKeys()
返回对象自身所有属性的键名数组(包含 Symbol 和不可枚举)。
const sym = Symbol('id');
const obj = {
[sym]: 1,
b: 2,
a: 3
};
Object.defineProperty(obj, 'c', {
value: 4,
enumerable: false
});
console.log(Reflect.ownKeys(obj));
// 输出: ['b', 'a', 'c', Symbol(id)]
遍历顺序
以上 5 种方法遵循相同的遍历顺序:
const obj = {
2: 'two',
b: 'b',
1: 'one',
a: 'a',
[Symbol('s')]: 'symbol'
};
console.log(Reflect.ownKeys(obj));
// 输出: ['1', '2', 'b', 'a', Symbol(s)]
// 顺序:数值键升序 -> 字符串键按添加顺序 -> Symbol 键按添加顺序
方法对比表
| 方法 | 自身属性 | 继承属性 | 不可枚举 | Symbol |
|---|---|---|---|---|
| for…in | ✓ | ✓ | ✗ | ✗ |
| Object.keys() | ✓ | ✗ | ✗ | ✗ |
| Object.getOwnPropertyNames() | ✓ | ✗ | ✓ | ✗ |
| Object.getOwnPropertySymbols() | ✓ | ✗ | ✓ | ✓ |
| Reflect.ownKeys() | ✓ | ✗ | ✓ | ✓ |
关键点
for...in是唯一会遍历继承属性的方法,常配合hasOwnProperty过滤Object.keys()最常用,只返回自身可枚举的字符串键Reflect.ownKeys()最全面,等于Object.getOwnPropertyNames()+Object.getOwnPropertySymbols()- 遍历顺序固定:数值键升序 → 字符串键插入序 → Symbol 键插入序
Object.values()和Object.entries()与Object.keys()规则相同
目录