JS基础 - for 循环
for 循环的基础知识点
for 循环的执行机制
for 循环内含有三个语句 for( 语句1,语句2,语句3 ){ 自定义函数 }
第一次循环:
先执行第一个初始化语句,再执行第二个判断语句,如果判断符合则执行自定义函数,如果判断不符合则停止执行。
举个例子:
for (var a = 0; a < 5; a++) { console.log(a); }
上述代码的执行顺序:
- var a = 0;
- a < 5
- console.log(a)
- a++
之后的循环:
先执行第二个判断语句,对上一次执行第三个语句的结果进行判断(这里是 js 引擎底层对值进行了记忆),如果判断符合则执行自定义函数,如果判断不符合则停止执行。
for 循环中 var 和 let 的区别
for 循环中对初始化语句只会执行一次,先看个例子:
const a = [];
for (var i = 0; i < 5; i++) {
a[i] = () =>{
console.log(i)
}
}
a[2](); // 5
根据上述的执行机制可以看出:当前 a 数组的长度是 5, i 的值为 5
当我们取 a[2] 时返回的不是 2 而是 5,说明 for 循环内的第三个语句其实都是在修改同一个变量 i
需要注意的是,上面赋给数组 a 的是一个函数,执行函数的时候才会去读取变量 i ,如果把上面的代码修改一下,直接将变量 i 赋值给数组 a,因为数字不是引用类型,所以得到的数组 a 为 [0,1,2,3,4]
:
const a = [];
for (var i = 0; i < 5; i++) {
a[i] = i;
}
a[2]; // 2
回到最初的代码,如果把 var 替换成 let:
const a = [];
for (let i = 0; i < 5; i++) {
a[i] = () =>{
console.log(i)
}
}
a[2](); // 2
这是能够打印出预期的结果,那么同样是执行一次初始化语句,为什么 let 能够保持 i 的值呢?是因为 Js 引擎在 for 循环到 let 初始化变量时,会生成多个块级作用域,这些块级作用域中的值互不影响,所以能够保持各自独立的值。
现在在 for 循环之后添加一个 console 语句:
for (var i = 0; i < 5; i++) {
// whatever
}
console.log( i ) // 5
for (let i = 0; i < 5; i++) {
// whatever
}
console.log( i ) // ReferenceError: i is not defined
原因也很好理解:var 存在着变量提升,所以使用 var 来初始化时,后续的代码也能够访问到初始化的变量。
如果将 let 从语句1中提出来,会是什么样的:
const a = [];
let i = 0;
for ( ;i < 5; i++) {
a[i] = () =>{
console.log(i)
}
}
a[2](); // 5
因为此时 let 已经不受 for 循环的控制了,无法生成多个块级作用域,所以与 var 的效果一致。
在 for 循环中改进 var
使用闭包可以让 var 声明达到与 let 一致的效果,具体的解释在《理解闭包》文章中有说明。
for (var i = 0; i < 5; i++) {
(function(n){
setTimeout(() => console.log(n), 1000)
})(i)
} // 0 1 2 3 4
for 循环遇到定时器
将上面的代码稍微变动一下:
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 1000)
} // 5 5 5 5 5
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 1000)
} // 0 1 2 3 4
其实和上述的原理是一致的,var 生成了一个公用的变量,而 let 生成了多个独立的块级作用域。
其它循环方法
除了 for 循环外,还有 while
和 do...while
方法可以实现循环,他们两者的区别就在于 while 先判断条件后执行,do…while 先执行后判断条件:
do
statement
while (expression);
// or
do {
statement
} while (expression);
与 for 循环相比 while 循环增加了 continue 方法来中止本轮循环,但它们都可以使用 break 方法来跳出循环:
var i = 0;
while (i < 10){
i++;
if (i%2 === 0) continue;
console.log(i);
} // 1,3,5,7,9
for (var i = 0; i < 5; i++) {
console.log(i);
if (i === 3) break;
} // 0,1,2,3
JS基础 - for 循环