JavaScript for 循环
上一篇的 while 循环把初始值、条件、更新三部分拆开写,代码能正常运行,但三部分分散各处,读起来要来回找。for 循环把这三部分集中到一行,是实际开发里用得最多的循环。这篇就讲 for 循环。
for 的三段式结构
for 括号里用两个分号隔开三段,依次是初始化、条件、更新。
for (初始化; 条件; 更新) {
// 循环体
}
执行顺序是初始化只跑一次,然后判断条件,为 true 执行循环体,执行完跑更新语句,再判断条件,如此反复。用 for 重写 1 加到 100
let sum = 0;
for (let i = 1; i <= 100; i++) {
sum = sum + i;
}
console.log(sum); // 输出 5050
对比上一篇的 while 写法,三要素都集中在一行里,条件更新不容易漏写。按固定次数循环用 for 更合适,while 适合条件本身比较复杂的情况。
遍历数组
for 最常见的用途是按索引遍历数组。数组是装多个值的数据结构,用方括号创建,按下标访问元素,arr[0] 是第一个元素,arr.length 是元素个数。
const fruits = ['苹果', '香蕉', '橘子'];
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
输出结果
苹果
香蕉
橘子
i 从 0 到 length - 1,正好覆盖数组每个元素。这种写法在后面讲数组的文章里会大量使用。如果只想按顺序取出每个值,不想管下标,ES6 还提供了 for…of 写法,一句带过,后面数组教程再细讲。
for (const fruit of fruits) {
console.log(fruit);
}
continue 跳过本次迭代
break 是结束整个循环,continue 是跳过本次迭代,直接进入下一次。比如只输出 1 到 10 里的偶数
for (let i = 1; i <= 10; i++) {
if (i % 2 !== 0) {
continue; // 奇数跳过,不执行下面的输出
}
console.log(i);
}
输出结果
2
4
6
8
10
i 为奇数时执行 continue,本次循环体剩下的代码不执行,直接进入 i++ 和下一次判断。
循环变量用 let 的好处
for 的初始化语句里用 let 声明循环变量,这个变量只在 for 的花括号里有效,外面访问不到。
for (let i = 0; i < 3; i++) {
console.log(i);
}
console.log(i); // 报错,i 在块外不存在
更重要的特性是每次迭代都会创建独立的变量绑定。把函数存到数组里,用 let 时每个函数记住的是自己那一轮的 i 值。
const fns = [];
for (let i = 0; i < 3; i++) {
fns.push(function () {
console.log(i);
});
}
fns[0](); // 输出 0
fns[1](); // 输出 1
fns[2](); // 输出 2
如果换成 var(旧语法),三个函数会输出同一个值 3。因为 var 没有块级作用域,所有迭代共享同一个变量。这也是本教程坚持用 let 的重要原因,后面讲闭包时会再次遇到这个特性。
嵌套循环
循环体里还可以再写循环,叫嵌套循环。外层每执行一次,内层要完整跑完一轮。经典例子是九九乘法表
for (let i = 1; i <= 9; i++) {
let line = '';
for (let j = 1; j <= i; j++) {
line = line + j + '*' + i + '=' + i * j + ' ';
}
console.log(line);
}
每行由内层循环拼接而成,i 固定时 j 从 1 跑到 i。嵌套循环在遍历二维结构时很常用,先理解外层走一圈、内层走完一轮的顺序。
小结
- for 的三段式结构把初始化、条件、更新集中在一行,执行顺序是初始化、判断、循环体、更新、再判断。
- 按索引遍历数组是最常见用法,i 从 0 到 length - 1,用 arr[i] 访问元素。
- continue 跳过本次迭代继续下一次,break 结束整个循环。
- 循环变量用 let 时拥有块级作用域,每次迭代都是独立绑定,这是本教程不用 var 的原因之一。
- 循环可以嵌套,外层每执行一次内层完整执行一轮。