for、for in、for of、forEach的认识

46 阅读3分钟

数组是前端开发中最基础的线性数据结构。数组在内存中是连续存储的,这赋予了它下标访问 O(1)  的极致性能。

但在 JavaScript 中,遍历这个线性结构的方法却五花八门。很多新手(甚至老手)都在混用 for、forEach、for...in 和 for...of。

今天我们不谈虚的,直接通过源码拆解,彻底搞懂它们的本质区别。


第一关:for

它是 JS 循环的鼻祖,虽然写法繁琐,但拥有最高的控制权

JavaScript

for(let i = 0; i < 10; i++){
    // i 拥有自己的块级作用域(Block Scope)
    setTimeout(function(){
        // 闭包特性:这里的 i 能正确捕获每次循环的值
        console.log(i); 
    }, 1000)
}
  • 核心机制:基于下标索引驱动。你可以完全掌控 i 的起始、结束和步长。

  • 亮点:1)代码中使用了 let。在 ES6 之前,用 var 会导致异步陷阱(打印出10个10),而 let 为每次循环创建了独立的词法环境,完美解决了异步回调中的变量共享问题。

    2)计数循环,cpun工作契合

  • 适用场景:需要精准控制索引、倒序遍历、或者需要中途修改步长时。


第二关:for...in

千万别用它来遍历数组!  这是很多人的误区。

JavaScript

const obj = {
    name: "张三",
    hobbies: ["篮球", "足球"]
}

// 1. 遍历对象:正确用法
for(let k in obj){
    console.log(k, obj[k]); // 输出 key 和 value
}

// 2. 遍历数组:错误/低效用法
const arr = [1, 2, 3];
for(let key in arr){
    console.log(key, arr[key]); 
}
  • 核心机制:for...in 是为遍历对象或json而设计的,for循环出的是key。

  • 致命缺陷(对数组而言)

    1. key 是字符串:在数组中,key 会变成 "0", "1",而不是数字索引,可能导致计算错误。
    2. 不仅遍历数组元素:如果你给 Array.prototype 加了自定义方法,for...in 也会把它们遍历出来!
    3. 顺序不保证:在某些旧浏览器引擎下,遍历顺序可能不遵循数组下标顺序。

第三关:for...of

这是 ES6 带来的福音,它是最符合直觉的遍历方式。

JavaScript

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

// 语义清晰,无需管理索引
for(let item of arr){
    console.log(item); // 直接拿到 Value
    if(item === 3) break; // 支持中断
}
  • 核心机制:遍历的是 Value(值)

  • 优势

    1. 语法最简洁:没有 i,没有 length,直击数据本身。
    2. 支持中断:可以使用 break、continue 和 return。
    3. 万能迭代:不仅支持数组,对象,还支持 String、Map、Set、NodeList 等所有部署了 Iterator 接口的数据结构。
  • 缺点:无法直接获取索引(index),如果需要索引,得配合 arr.entries() 使用。


第四关:forEach 

数组自带的高阶函数,属于声明式编程。

JavaScript

const arr = [1, 2, 3];
arr.forEach((item, index) => {
    console.log(item);
    // return; // 只能跳过本次回调,无法停止整个循环!
    // break;  // 报错!
});
  • 核心机制:接收一个回调函数,对数组每一项执行操作。
  • 硬伤无法中途终止!  一旦开始,它就会像吃了炫迈一样,直到遍历完所有元素(除非抛出异常),且性能较差。
  • 适用场景:确定需要处理所有元素,且不需要返回值的场景(例如单纯的数据打印、DOM修改)。

总结

学习for ,for in , for of , forEach 主要是对基础的一个回顾,对于要从不同的数据类型中提取出想要的数据,考虑要使用哪个效果更好,并且满足自己的需求,比如遍历过程中要提前终止...我们就不能考虑forEach。

好了今天就到这里