数组对象遍历方式

JS 数组和对象的遍历方法及比较

问题

JavaScript 中数组和对象有哪些遍历方式?它们之间有什么区别?

解答

数组遍历

const arr = [1, 2, 3, 4, 5];

// 1. for 循环 - 最基础,可 break/continue
for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

// 2. for...of - ES6,遍历值,可 break
for (const item of arr) {
  console.log(item);
}

// 3. forEach - 无返回值,不可中断
arr.forEach((item, index) => {
  console.log(item, index);
});

// 4. map - 返回新数组
const doubled = arr.map(item => item * 2);
// [2, 4, 6, 8, 10]

// 5. filter - 返回符合条件的新数组
const evens = arr.filter(item => item % 2 === 0);
// [2, 4]

// 6. reduce - 累计计算
const sum = arr.reduce((acc, cur) => acc + cur, 0);
// 15

// 7. some - 有一个满足就返回 true
const hasEven = arr.some(item => item % 2 === 0);
// true

// 8. every - 全部满足才返回 true
const allPositive = arr.every(item => item > 0);
// true

// 9. find - 返回第一个满足条件的元素
const found = arr.find(item => item > 3);
// 4

// 10. findIndex - 返回第一个满足条件的索引
const foundIndex = arr.findIndex(item => item > 3);
// 3

对象遍历

const obj = { a: 1, b: 2, c: 3 };

// 原型上添加属性用于测试
Object.prototype.inherited = 'inherited';

// 1. for...in - 遍历可枚举属性,包括原型链
for (const key in obj) {
  console.log(key); // a, b, c, inherited
}

// 配合 hasOwnProperty 过滤原型属性
for (const key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(key); // a, b, c
  }
}

// 2. Object.keys() - 返回自身可枚举属性的键数组
Object.keys(obj).forEach(key => {
  console.log(key, obj[key]); // a 1, b 2, c 3
});

// 3. Object.values() - 返回自身可枚举属性的值数组
Object.values(obj).forEach(value => {
  console.log(value); // 1, 2, 3
});

// 4. Object.entries() - 返回 [key, value] 数组
Object.entries(obj).forEach(([key, value]) => {
  console.log(key, value); // a 1, b 2, c 3
});

// 5. Object.getOwnPropertyNames() - 包括不可枚举属性
const obj2 = {};
Object.defineProperty(obj2, 'zzinb', {
  value: 'secret',
  enumerable: false
});
obj2.visible = 'show';

console.log(Object.keys(obj2)); // ['vkonk']
console.log(Object.getOwnPropertyNames(obj2)); // ['zzinb', 'vkonk']

// 清理测试属性
delete Object.prototype.inherited;

方法对比

方法返回值可中断遍历原型链适用场景
for--需要索引或中断
for…of--遍历可迭代对象
forEachundefined-简单遍历
map新数组-转换数据
filter新数组-筛选数据
reduce累计值-聚合计算
for…in-遍历对象属性
Object.keys键数组-获取对象键

性能比较

const largeArr = Array.from({ length: 100000 }, (_, i) => i);

console.time('for');
for (let i = 0; i < largeArr.length; i++) {
  largeArr[i];
}
console.timeEnd('for'); // 最快

console.time('for...of');
for (const item of largeArr) {
  item;
}
console.timeEnd('for...of'); // 较快

console.time('forEach');
largeArr.forEach(item => {
  item;
});
console.timeEnd('forEach'); // 中等

// 性能排序(通常情况):for > for...of > forEach > map

关键点

  • for 循环性能最好,支持 break/continue,适合需要精确控制的场景
  • for…of 遍历值,for…in 遍历键;for…in 会遍历原型链属性
  • forEach 无法中断,return 只能跳过当前迭代
  • map/filter/reduce 是函数式编程风格,返回新数据,不修改原数组
  • Object.keys/values/entries 只遍历自身可枚举属性,比 for…in 更安全