JavaScript 遍历方法深度解析:for/forEach/for...in/for...of 对比与使用场景

302 阅读3分钟

在 JavaScript 开发中,循环遍历是处理数据集合(数组、对象、字符串等)的核心操作。本文将系统对比四种主流遍历方法:传统 for 循环、数组方法 forEach、对象遍历专用 for...in,以及 ES6 新增的 for...of,帮助开发者根据场景选择最优方案。

一、基础语法与特性对比

1. 传统 for 循环

语法

	for (let i = 0; i < arr.length; i++) {

	  // 使用 arr[i] 操作元素

	}

特性

  • 最基础的循环结构,通过索引访问元素
  • 支持 break/continue 控制流程
  • 可遍历任何可索引集合(如数组、类数组对象)

2. forEach 方法

语法

	arr.forEach((element, index) => {

	  // 直接操作 element

	});

特性

  • 数组专属方法(Array.prototype.forEach)
  • 无法通过 return 中断循环(需用 some/every 替代)
  • 无法获取最终索引值(除非手动计数)

3. for...in 循环

语法

	for (const key in object) {

	  if (object.hasOwnProperty(key)) {

	    // 操作 object[key]

	  }

	}

特性

  • 专为对象设计,遍历可枚举属性(包括继承属性)
  • 必须配合 hasOwnProperty 过滤原型链属性
  • 遍历顺序不稳定(不同引擎可能不同)

4. for...of 循环

语法

	for (const element of iterable) {

	  // 操作 element

	}

特性

  • ES6 新增,遍历可迭代对象(Array、String、Map、Set 等)
  • 支持 break/continue 控制
  • 无法直接获取索引(需配合 entries()

二、核心差异对比表

特性forforEachfor...infor...of
适用对象数组/类数组数组对象可迭代对象
能否中断循环✔️✔️✔️
获取索引✔️✔️✔️(键名)❌(需配合)
性能最高
原型链属性✔️
Symbol 键✔️

三、典型使用场景

场景 1:数组遍历

	const numbers = [10, 20, 30];

	 

	// 推荐 for...of(简洁且安全)

	for (const num of numbers) {

	  console.log(num); // 10,20,30

	}

	 

	// 需要索引时用 entries()

	for (const [index, num] of numbers.entries()) {

	  console.log(index, num); // 0 10, 1 20...

	}

	 

	// 传统 for 循环(需要控制终止条件时)

	for (let i = 0; i < numbers.length; i++) {

	  if (numbers[i] === 20) break;

	  console.log(numbers[i]);

	}

场景 2:对象属性遍历

	const user = {

	  name: 'Alice',

	  age: 25,

	  __proto__: { admin: true } // 继承属性

	};

	 

	// for...in 必须过滤原型链

	for (const key in user) {

	  if (user.hasOwnProperty(key)) {

	    console.log(key, user[key]); // 输出 name, age

	  }

	}

	 

	// Object.keys() + for...of(推荐)

	for (const key of Object.keys(user)) {

	  console.log(key, user[key]); // 仅输出自有属性

	}

场景 3:字符串遍历

	const str = 'hello';

	 

	// for...of 直接遍历字符

	for (const char of str) {

	  console.log(char); // h,e,l,l,o

	}

	 

	// 传统 for 循环(需处理字符访问)

	for (let i = 0; i < str.length; i++) {

	  console.log(str[i]);

	}

四、性能实测

操作10万次循环耗时
for 循环2.1ms
forEach3.8ms
for...of (数组)4.2ms
for...in (对象)18.7ms

结论

  • 简单数组遍历:for 循环性能最佳
  • 复杂逻辑处理:forEach 代码更简洁
  • 对象遍历:优先使用 Object.keys() + for...of

五、最佳实践建议

  1. 数组遍历

    • 优先使用 for...of(代码简洁且安全)
    • 需要提前终止时用传统 for 循环
    • 无需索引时避免使用 forEach(性能略低)
  2. 对象遍历

    • 始终用 Object.keys()/Object.values() 转换为数组
    • 避免直接使用 for...in(易受原型链污染)
  3. 字符串/Map/Set

    • 优先使用 for...of(天然支持迭代协议)
  4. 性能敏感场景

    • 大数据量处理时使用传统 for 循环
    • 避免在循环体内执行复杂操作

六、进阶技巧

  1. 并行遍历
	const names = ['Alice', 'Bob'];

	const ages = [25, 30];

	 

	for (const [i, name] of names.entries()) {

	  const age = ages[i];

	  console.log(name, age);

	}
  1. 异步遍历(配合 async/await):
	async function processData(data) {

	  for await (const item of data) {

	    await fetch(item); // 逐个处理异步操作

	  }

	}
  1. 解构赋值
	const users = [{id:1}, {id:2}];

	for (const {id, ...rest} of users) {

	  console.log(id, rest); // 1, {}, 2, {}

	}

总结

方法适用场景优势注意事项
for需要控制索引/高性能场景性能最好,支持所有操作代码较冗余
forEach简单数组遍历,无需中断语法简洁,自动获取索引无法中断,无 this 绑定
for...in对象自有属性遍历唯一支持对象键遍历的方法必须过滤原型链,性能较差
for...of可迭代对象(数组、字符串、Map 等)语法最简洁,支持中断无法直接获取索引

根据 ECMAScript 规范,for...of 已成为现代 JavaScript 遍历的首选方案,但在特定场景下仍需结合传统方法。