数组是前端开发中最基础的线性数据结构。数组在内存中是连续存储的,这赋予了它下标访问 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。
-
致命缺陷(对数组而言) :
- key 是字符串:在数组中,key 会变成 "0", "1",而不是数字索引,可能导致计算错误。
- 不仅遍历数组元素:如果你给 Array.prototype 加了自定义方法,for...in 也会把它们遍历出来!
- 顺序不保证:在某些旧浏览器引擎下,遍历顺序可能不遵循数组下标顺序。
第三关: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(值) 。
-
优势:
- 语法最简洁:没有 i,没有 length,直击数据本身。
- 支持中断:可以使用 break、continue 和 return。
- 万能迭代:不仅支持数组,对象,还支持 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。
好了今天就到这里