研究对象
本文仅对比分析for
、for...in
、for...of
与 forEach
核心差异概览
特性 | for | for...in | for...of | forEach |
---|---|---|---|---|
适用对象 | 通用 | 对象属性 | 可迭代对象值 | 数组元素 |
遍历内容 | 索引/自定义逻辑 | 键名(含继承属性) | 值(直接访问) | 元素/索引/数组本身 |
中断能力 | ✅ break/continue | ✅ break/continue | ✅ break/continue | ❌(需异常抛出) |
性能表现 | 最高 | 中等 | 高 | 中等 |
ES6+ 数据结构 | ❌ | ❌ | ✅ Map/Set等 | ❌ |
各循环结构详解
1. for
循环:精准控制的传统方案
语法模板
for (初始化; 条件; 迭代) {
// 循环体
}
核心用途
- 需要精确控制迭代逻辑的场景(如复杂步长、提前退出)
- 大规模数据遍历(性能敏感场景)
关键特性
const arr = [10, 20, 30];
for (let i = 0; i < arr.length; i++) {
if (arr[i] > 15) break; // 支持中断
console.log(arr[i] * 2); // 20
}
- 🔹 手动管理索引,灵活控制循环流程
- 🔹 唯一支持完整循环控制(break/continue/return)
- 🔹 浏览器引擎级优化,性能天花板
2. for...in
:对象属性遍历工具
语法模板
for (const key in object) {
// 循环体
}
核心用途
- 遍历对象自有及原型链上的可枚举属性
- 不推荐用于数组遍历
关键特性
const obj = { name: 'John', age: 30 };
for (const key in obj) {
if (obj.hasOwnProperty(key)) { // 过滤继承属性
console.log(`${key}: ${obj[key]}`);
}
}
- 🔸 遍历顺序不固定(依赖对象属性定义顺序)
- 🔸 可能意外遍历到原型链属性(需配合
hasOwnProperty
) - 🔸 对稀疏数组会跳过空位
3. for...of
:现代迭代协议实践者
语法模板
for (const value of iterable) {
// 循环体
}
核心用途
- 遍历实现了
[Symbol.iterator]
的对象 - 替代传统循环的现代化方案
关键特性
const set = new Set([1, 2, 3]);
for (const num of set) {
console.log(num ** 2); // 1, 4, 9
}
- 🔹 直接访问值而非索引
- 🔹 支持 Map/Set/字符串等 ES6+ 数据结构
- 🔹 自动迭代器管理,避免越界错误
4. forEach
:数组专属函数式方案
语法模板
array.forEach((item, index, arr) => {
// 回调逻辑
});
核心用途
- 简单的数组遍历操作
- 函数式编程范式实践
关键特性
const tasks = ['login', 'fetch', 'render'];
tasks.forEach((task, idx) => {
if (task === 'fetch') return; // 仅跳过当前迭代
console.log(`Step ${idx}: ${task}`);
});
- 🔸 无法中断循环(需抛出异常强制终止)
- 🔸 自动绑定元素上下文(第三参数为原数组)
- 🔸 链式调用友好(配合 map/filter 使用)
性能与选择策略
-
性能优先级
for
>for...of
>for...in
≈forEach
-
现代开发建议
- 优先使用
for...of
处理可迭代对象 - 性能关键路径使用传统
for
循环 - 对象遍历使用
for...in
+hasOwnProperty
组合 - 简单的数组操作可选用
forEach
- 优先使用
-
避免陷阱
// 错误示范:用 for...in 遍历数组 const arr = [1, 2, 3]; arr.customProp = 'test'; for (const key in arr) { console.log(key); // 输出 0,1,2,customProp }
升级方案
考虑使用现代 API 提升代码质量:
// 使用 Array.prototype.entries()
for (const [index, value] of arr.entries()) {
// 同时获取索引和值
}
// 对象遍历新方案
Object.entries(obj).forEach(([key, val]) => {
// 安全遍历对象属性
});
通过合理选择循环方式,可显著提升代码执行效率和可维护性。