如何用JavaScript遍历对象的所有属性
在JavaScript开发中,我们经常需要获取对象的所有属性来进行数据处理、校验或者序列化等操作。不同的遍历方式适用的场景有所区别,下面我们将介绍几种常用的对象属性遍历方法,并说明它们的特点和适用场景。
一、for...in 循环遍历
for...in 是最基础的对象属性遍历方式,它会遍历对象自身以及原型链上所有可枚举的属性。如果只需要获取对象自身的属性,通常需要配合 hasOwnProperty 方法进行过滤。
// 定义示例对象
const user = {
name: '张三',
age: 25,
gender: '男'
};
// 给对象原型链添加可枚举属性
Object.prototype.commonProp = '原型属性';
// 使用for...in遍历所有可枚举属性(包含原型链)
console.log('for...in遍历所有可枚举属性:');
for (const key in user) {
console.log(`属性名:${key},属性值:${user[key]}`);
}
// 过滤只保留对象自身的属性
console.log('\nfor...in遍历自身属性:');
for (const key in user) {
if (user.hasOwnProperty(key)) {
console.log(`属性名:${key},属性值:${user[key]}`);
}
}上面的代码中,for...in 第一次遍历会输出 user 对象自身的 name、age、gender 以及原型链上的 commonProp 属性。添加 hasOwnProperty 判断后,只会输出对象自身的三个属性,避免获取到原型链上的多余属性。
二、Object.keys() 方法遍历
Object.keys() 方法会返回一个由对象自身所有可枚举属性的属性名组成的数组,之后我们可以使用数组的遍历方法(如 forEach、map 等)来处理这些属性,这种方式只会获取对象自身的属性,不会包含原型链上的属性。
const user = {
name: '张三',
age: 25,
gender: '男'
};
// 给对象原型链添加可枚举属性
Object.prototype.commonProp = '原型属性';
// 获取对象自身所有可枚举属性的键名数组
const keys = Object.keys(user);
console.log('Object.keys()返回的键名数组:', keys);
// 遍历键名数组处理属性
console.log('遍历对象自身属性:');
keys.forEach(key => {
console.log(`属性名:${key},属性值:${user[key]}`);
});这种方式的优势是返回的是数组,我们可以利用数组的各种方法灵活处理属性,同时默认只会获取对象自身的可枚举属性,不需要额外做原型链过滤,使用起来更简洁。
三、Object.getOwnPropertyNames() 方法遍历
Object.getOwnPropertyNames() 方法会返回对象自身所有属性的属性名数组,不管属性是否可枚举,这一点和 Object.keys() 有明显区别。如果对象中有不可枚举的属性,也需要获取到的话,可以使用这个方法。
const user = {
name: '张三',
age: 25
};
// 给user对象添加一个不可枚举的属性
Object.defineProperty(user, 'gender', {
value: '男',
enumerable: false // 设置为不可枚举
});
// Object.keys()只会获取可枚举属性
console.log('Object.keys()结果:', Object.keys(user));
// Object.getOwnPropertyNames()会获取所有自身属性,包括不可枚举的
console.log('Object.getOwnPropertyNames()结果:', Object.getOwnPropertyNames(user));
// 遍历所有自身属性(含不可枚举)
console.log('遍历所有自身属性:');
Object.getOwnPropertyNames(user).forEach(key => {
console.log(`属性名:${key},属性值:${user[key]}`);
});可以看到,Object.keys() 只返回了 name 和 age 两个可枚举属性,而 Object.getOwnPropertyNames() 还返回了不可枚举的 gender 属性,适合需要获取对象所有自身属性的场景。
四、Reflect.ownKeys() 方法遍历
Reflect.ownKeys() 方法会返回对象自身的所有属性名,包括不可枚举属性和 Symbol 类型的属性,是覆盖范围最广的自身属性遍历方法。如果对象中存在 Symbol 作为属性键的情况,用这个方法可以全部获取到。
// 定义一个Symbol作为属性键
const salarySymbol = Symbol('salary');
const user = {
name: '张三',
age: 25
};
// 添加不可枚举的字符串属性
Object.defineProperty(user, 'gender', {
value: '男',
enumerable: false
});
// 添加Symbol类型的属性
user[salarySymbol] = 15000;
// Reflect.ownKeys()返回所有自身属性键
const allKeys = Reflect.ownKeys(user);
console.log('Reflect.ownKeys()返回的所有键:', allKeys);
// 遍历所有键
console.log('遍历所有自身属性:');
allKeys.forEach(key => {
console.log(`属性名:${String(key)},属性值:${user[key]}`);
});上面的代码中,Reflect.ownKeys() 返回的数组包含了字符串键 name、age、gender 以及 Symbol 类型的 salarySymbol,能够完整覆盖对象自身的各类属性。
五、不同遍历方式对比
为了更清晰地选择适合的遍历方式,我们将几种方法的特性整理成表格对比:
| 遍历方式 | 是否包含原型链属性 | 是否包含不可枚举属性 | 是否包含Symbol属性 | 适用场景 |
|---|---|---|---|---|
| for...in | 是 | 否 | 否 | 需要遍历原型链可枚举属性时使用,需配合hasOwnProperty过滤自身属性 |
| Object.keys() | 否 | 否 | 否 | 只需要获取对象自身可枚举的字符串属性时使用 |
| Object.getOwnPropertyNames() | 否 | 是 | 否 | 需要获取对象自身所有字符串属性(含不可枚举)时使用 |
| Reflect.ownKeys() | 否 | 是 | 是 | 需要获取对象自身所有属性(含Symbol、不可枚举)时使用 |
六、注意事项
- 如果不需要原型链上的属性,优先选择 Object.keys()、Object.getOwnPropertyNames()、Reflect.ownKeys() 这几种方法,避免额外的过滤逻辑。
- 处理不可枚举属性或者 Symbol 属性时,要根据实际需求选择对应的方法,不要盲目使用覆盖范围最广的 Reflect.ownKeys(),避免获取到不需要的属性。
- 遍历过程中如果修改了对象的属性,可能会影响遍历结果,建议在遍历前先拷贝属性列表,或者避免在遍历时修改原对象的属性结构。