for、for-in、for-of
在用JavaScript编写代码的时候,不可避免地要遇到循环遍历数组并对数组做一些相应的操作。在JavaScript中有很多方法可以遍历数组。最普通的是for循环遍历,以及 for-in 和 for-of,还有forEach和map函数也可以用来对数组进行操作。
普通的for循环写法很简单,定义一个循环变量 i,通过比较i与数组长度的值来实现是否结束循环,在每一次循环过后都执行i++(即将i的值加1)。
for-in 和 for-of 相较比较类似,都是定义一个循环变量,不同的是该循环变量对应的意义不同,for-in定义的循环变量是每次遍历的数组元素的索引,而for-of定义的循环变量是每次循环遍历的数组元素本身。所以在for-in循环中,可以通过 arr[i] 来访问数组元素,而在for-of循环中,可以使用 i 直接来访问数组变量。
// 普通for循环
for(var i=0;i<arr.length;i++){
// do something
}
// for-in
for(var i in arr){
// do something
}
// for-of
for(var i of arr){
// do someting
}
值得注意的是因为JavaScript的变量机制,使用关键字 var 定义的变量不仅会被提升,而且会被注册为当前作用域的变量,假如在全局作用域里边有一个for循环语句 for(var i=0;i<arr.length;i++){...},var 关键字会将i注册为一个全局变量,亦即可以在循环外部通过 window.i 或 i 来访问到,使用 let 定义循环变量就不会有这种情况发生。for-in 和 for-of 循环使用 var 关键字定义的循环变量也会出现这种情况。
另外值得注意的是,当在for循环里面写异步代码的时候,也会有意想不到的情况发生,考虑如下的代码:
var arr = [0,1,2,3,4]
for(var i=0;i<arr.length;i++){
setTimeout(function(){
console.log(i)
},1000)
}
该处的代码在执行的时候会以一秒的时间间隔,依次输出五个5,而不是依次输出 1 2 3 4 5。我认为的一个原因是因为js的事件循环机制会先执行for语句,但是忽略其内的异步代码,等所有的同步代码执行完毕以后,再执行 setTimeout() 函数,那个时候 i 的值已经变成了5。
但是令人感到奇怪的是将上面代码中的 var 换成 let 后,输出结果是 0 1 2 3 4。我猜想是每次执行循环的时候,在将 setTimeout 代码放入宏任务队列时,同时也会将相关的变量也一块放进去,只有这样才会出现这样的输出结果。
当把上面代码中的for循环改写成for-in的形式时,可以在控制台中观察到连续输出了四个4,将var改写成 let 时,输出结果为 1 2 3 4,跟上面的描述比较相似。
forEach、map
forEach() 和 map 函数都接收一个匿名函数作为参数,该函数可以定义一些针对每次循环遍历中针对数组元素的操作。所不同的是 forEach 不会返回,map会将处理结果作为一个新的数组返回。因此map适合用在需要将数组里面的元素经过处理后返回一个新数组的场景。
var arr = [0,1,3,4]
arr.forEach((ele,i) => {
console.log(ele,i)
})
// 将 arr 中每个元素的值变成2倍
var arr1 = arr.map(ele => {
return ele*2
})
arr1 // [0,2,6,8]