for 循环是用来重复执行某些逻辑的最常用语句之一。
在 JavaScript 中,它由 for 关键字、一对圆括号中的_头部_,以及一个代码块组成,代码块用花括号括起来,里面是循环的_循环体_。
for (initialization; condition; step) {
// code that is executed repeatedly as long as the condition is
// true
}
初始化通常用来设置一个计数器变量,条件用来检查循环应该继续还是停止,步进则在每一轮重复结束时让计数器自增。 头部的各个部分之间用分号分隔。
const list = ['a', 'b', 'c'];
for (let i = 0; i < list.length; i++) {
// code that should be executed for each item in the array
}
头部这三个部分都是可选的。 实际中很少这么用。 你可以在 MDN 文档 中了解更多。
for 循环for 循环可以嵌套,例如用来遍历嵌套的(多维)数组。
注意为每个循环设置不同的计数器变量。
const coords = [
[1, 2],
[4, 7],
[10, -3],
];
for (let i = 0; i < coords.length; i++) {
for (let j = 0; j < coords[i].length; j++) {
// do something with coords[i][j]
}
}
在循环体中,你可以用 break 关键字彻底停止循环的执行。
相比之下,continue 关键字只停止当前这一次迭代的执行,然后继续下一次。
处理嵌套循环时,默认情况下 break 和 continue 总是作用于最内层的循环。
你可以用标签来改变这一行为。
标签是一个标识符名称,后面跟一个冒号,放在循环的前面(或上方)。
然后就可以把标签和 break 或 continue 组合起来,指明该语句应该作用于哪个循环。
outer: for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
// ...
if (j > 5) {
continue outer;
}
// ...
}
}
处理异步代码时,你需要小心,正确声明计数器变量。
我们来看一个例子:等待 1 秒后,用 setTimeout 异步累加计数器变量。
如果用 var 声明计数器,或者用 let 但在头部之外声明,代码就无法得到预期的结果。
let sum = 0;
for (var i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// eventually sum will be 12 instead of 6 (1+2+3)
let sum = 0;
let i;
for (i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// same here, eventually sum will be 12 instead of 6 (1+2+3)
在这两种情况下,i 的作用域都不局限于某一次具体的循环迭代。
等到求和计算发生时,i 已经到达了它的最终值 4,于是总和成了 4 + 4 + 4 = 12。
只要在头部用 let 声明计数器,就能避免这个问题。
这样做的特别之处在于,每次迭代都会得到自己独有的变量 let i,它的作用域恰好是循环体的那一次执行。
因此稍后计算总和时,每个回调函数引用的都是自己那个变量 i,其中仍然保存着正确的值。
let sum = 0;
for (let i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// eventually sum will be 6 (1+2+3) as expected