咱们常常须要重复执行一些操做。javascript
例如,咱们须要将列表中的商品逐个输出,或者运行相同的代码将数字 1 到 10 逐个输出。html
循环 是一种重复运行同一代码的方法。java
while
循环的语法以下:react
while (condition) {
// 代码
// 所谓的“循环体”
}
复制代码
当 condition
为 true
时,执行循环体的 code
。算法
例如,如下将循环输出当 i < 3
时的 i
值:浏览器
let i = 0;
while (i < 3) { // 依次显示 0、1 和 2
alert( i );
i++;
}
复制代码
循环体的单次执行叫做 一次迭代。上面示例中的循环进行了三次迭代。bash
若是上述示例中没有 i++
,那么循环(理论上)会永远重复执行下去。实际上,浏览器提供了阻止这种循环的方法,咱们能够经过终止进程,来停掉服务器端的 JavaScript。服务器
任何表达式或变量均可以是循环条件,而不只仅是比较。在 while
中的循环条件会被计算,计算结果会被转化为布尔值。微信
例如,while (i != 0)
可简写为 while (i)
:学习
let i = 3;
while (i) { // 当 i 变成 0 时,条件为 false,循环终止
alert( i );
i--;
}
复制代码
若是循环体只有一条语句,则能够省略大括号 {…}
:
let i = 3;
while (i) alert(i--);
复制代码
使用 do..while
语法能够将条件检查移至循环体 下面:
do {
// 循环体
} while (condition);
复制代码
循环首先执行循环体,而后检查条件,当条件为真时,重复执行循环体。
例如:
let i = 0;
do {
alert( i );
i++;
} while (i < 3);
复制代码
这种形式的语法不多使用,除非你但愿无论条件是否为真,循环体 至少执行一次。一般咱们更倾向于使用另外一个形式:while(…) {…}
。
for
循环更加复杂,但它是最常使用的循环形式。
for
循环看起来就像这样:
for (begin; condition; step) {
// ……循环体……
}
复制代码
咱们经过示例来了解一下这三个部分的含义。下述循环从 i
等于 0
到 3
(但不包括 3
)运行 alert(i)
:
for (let i = 0; i < 3; i++) { // 结果为 0、一、2
alert(i);
}
复制代码
咱们逐个部分分析 for
循环:
语句段 | ||
---|---|---|
begin | i = 0 |
进入循环时执行一次。 |
condition | i < 3 |
在每次循环迭代以前检查,若是为 false,中止循环。 |
body(循环体) | alert(i) |
条件为真时,重复运行。 |
step | i++ |
在每次循环体迭代后执行。 |
通常循环算法的工做原理以下:
开始运行
→ (若是 condition 成立 → 运行 body 而后运行 step)
→ (若是 condition 成立 → 运行 body 而后运行 step)
→ (若是 condition 成立 → 运行 body 而后运行 step)
→ ...
复制代码
因此,begin
执行一次,而后进行迭代:每次检查 condition
后,执行 body
和 step
。
若是你这是第一次接触循环,那么回到这个例子,在一张纸上重现它逐步运行的过程,可能会对你有所帮助。
如下是在这个示例中发生的事:
// for (let i = 0; i < 3; i++) alert(i)
// 开始
let i = 0
// 若是条件为真,运行下一步
if (i < 3) { alert(i); i++ }
// 若是条件为真,运行下一步
if (i < 3) { alert(i); i++ }
// 若是条件为真,运行下一步
if (i < 3) { alert(i); i++ }
// ……结束,由于如今 i == 3
复制代码
这里“计数”变量 i
是在循环中声明的。这叫作“内联”变量声明。这样的变量只在循环中可见。
for (let i = 0; i < 3; i++) {
alert(i); // 0, 1, 2
}
alert(i); // 错误,没有这个变量。
复制代码
除了定义一个变量,咱们也可使用现有的变量:
let i = 0;
for (i = 0; i < 3; i++) { // 使用现有的变量
alert(i); // 0, 1, 2
}
alert(i); //3,可见,由于是在循环以外声明的
复制代码
for
循环的任何语句段均可以被省略。
例如,若是咱们在循环开始时不须要作任何事,咱们就能够省略 begin
语句段。
就像这样:
let i = 0; // 咱们已经声明了 i 并对它进行了赋值
for (; i < 3; i++) { // 再也不须要 "begin" 语句段
alert( i ); // 0, 1, 2
}
复制代码
咱们也能够移除 step
语句段:
let i = 0;
for (; i < 3;) {
alert( i++ );
}
复制代码
该循环与 while (i < 3)
等价。
实际上咱们能够删除全部内容,从而建立一个无限循环:
for (;;) {
// 无限循环
}
复制代码
请注意 for
的两个 ;
必须存在,不然会出现语法错误。
一般条件为假时,循环会终止。
但咱们随时均可以使用 break
指令强制退出。
例如,下面这个循环要求用户输入一系列数字,在输入的内容不是数字时“终止”循环。
let sum = 0;
while (true) {
let value = +prompt("Enter a number", '');
if (!value) break; // (*)
sum += value;
}
alert( 'Sum: ' + sum );
复制代码
若是用户输入空行或取消输入,在 (*)
行的 break
指令会被激活。它马上终止循环,将控制权传递给循环后的第一行,即,alert
。
根据须要,"无限循环 + break
" 的组合很是适用于没必要在循环开始/结束时检查条件,但须要在中间甚至是主体的多个位置进行条件检查的状况。
continue
指令是 break
的“轻量版”。它不会停掉整个循环。而是中止当前这一次迭代,并强制启动新一轮循环(若是条件容许的话)。
若是咱们完成了当前的迭代,而且但愿继续执行下一次迭代,咱们就可使用它。
下面这个循环使用 continue
来只输出奇数:
for (let i = 0; i < 10; i++) {
//若是为真,跳过循环体的剩余部分。
if (i % 2 == 0) continue;
alert(i); // 1,而后 3,5,7,9
}
复制代码
对于偶数的 i
值,continue
指令会中止本次循环的继续执行,将控制权传递给下一次 for
循环的迭代(使用下一个数字)。所以 alert
仅被奇数值调用。
显示奇数的循环能够像下面这样:
for (let i = 0; i < 10; i++) {
if (i % 2) {
alert( i );
}
}
复制代码
从技术角度看,它与上一个示例彻底相同。固然,咱们能够将代码包装在 if
块而不使用 continue
。
但在反作用方面,它多建立了一层嵌套(大括号内的 alert
调用)。若是 if
中代码有多行,则可能会下降代码总体的可读性。
break/continue
在‘?’的右边请注意非表达式的语法结构不能与三元运算符 ?
一块儿使用。特别是 break/continue
这样的指令是不容许这样使用的。
例如,咱们使用以下代码:
if (i > 5) {
alert(i);
} else {
continue;
}
复制代码
……用问号重写:
(i > 5) ? alert(i) : continue; // continue 不容许在这个位置
复制代码
……代码会中止运行,并显示有语法错误。
这只是不使用 ?
而不是 if
的另外一个缘由。
有时候咱们须要从一次从多层嵌套的循环中跳出来。
例如,下述代码中咱们的循环使用了 i
和 j
,从 (0,0)
到 (3,3)
提示坐标 (i, j)
:
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Value at coords (${i},${j})`, '');
// 若是我想从这里退出并直接执行 alert('Done!')
}
}
alert('Done!');
复制代码
咱们须要提供一种方法,以在用户取消输入时来中止这个过程。
在 input
以后的普通 break
只会打破内部循环。这还不够 —— 标签能够实现这一功能!
标签 是在循环以前带有冒号的标识符:
labelName: for (...) {
...
}
复制代码
break <labelName>
语句跳出循环至标签处:
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let input = prompt(`Value at coords (${i},${j})`, '');
// 若是是空字符串或被取消,则中断并跳出这两个循环。
if (!input) break outer; // (*)
// 用获得的值作些事……
}
}
alert('Done!');
复制代码
上述代码中,break outer
向上寻找名为 outer
的标签并跳出当前循环。
所以,控制权直接从 (*)
转至 alert('Done!')
。
咱们还能够将标签移至单独一行:
outer:
for (let i = 0; i < 3; i++) { ... }
复制代码
continue
指令也能够与标签一块儿使用。在这种状况下,执行跳转到标记循环的下一次迭代。
标签不容许咱们跳到代码的任意位置。
例如,这样作是不可能的:
break label; // 没法跳转到这个标签
label: for (...)
复制代码
只有在循环内部才能调用 break/continue
,而且标签必须位于指令上方的某个位置。
咱们学习了三种循环:
while
—— 每次迭代以前都要检查条件。do..while
—— 每次迭代后都要检查条件。for (;;)
—— 每次迭代以前都要检查条件,可使用其余设置。一般使用 while(true)
来构造“无限”循环。这样的循环和其余循环同样,均可以经过 break
指令来终止。
若是咱们不想在当前迭代中作任何事,而且想要转移至下一次迭代,那么可使用 continue
指令。
break/continue
支持循环前的标签。标签是 break/continue
跳出嵌套循环以转到外部的惟一方法。
先本身作题目再看答案。
重要程度:⭐️⭐️⭐
此代码最后一次 alert 值是多少?为何?
let i = 3;
while (i) {
alert( i-- );
}
复制代码
重要程度:⭐️⭐️⭐️⭐
对于每次循环,写出你认为会显示的值,而后与答案进行比较。
如下两个循环的 alert
值是否相同?
前缀形式 ++i
:
let i = 0;
while (++i < 5) alert( i );
复制代码
后缀形式 i++
let i = 0;
while (i++ < 5) alert( i ); 复制代码
重要程度:⭐️⭐️⭐️⭐
对于每次循环,写下它将显示的值。而后与答案进行比较。
两次循环 alert
值是否相同?
后缀形式:
for (let i = 0; i < 5; i++) alert( i );
复制代码
前缀形式:
for (let i = 0; i < 5; ++i) alert( i );
复制代码
重要程度:⭐️⭐️⭐️⭐️⭐️
使用 for
循环输出从 2
到 10
的偶数。
重要程度:⭐️⭐️⭐️⭐️⭐️
重写代码,在保证不改变其行为的状况下,将 for
循环更改成 while
(输出应保持不变)。
for (let i = 0; i < 3; i++) {
alert( `number ${i}!` );
}
复制代码
重要程度:⭐️⭐️⭐️⭐️⭐️
编写一个提示用户输入大于 100
的数字的循环。若是用户输入其余数值 —— 请他从新输入。
循环一直在请求一个数字,直到用户输入了一个大于 100
的数字,取消输入或输入了一个空行为止。
在这咱们假设用户只会输入数字。在本题目中,不须要对非数值输入进行特殊处理。
重要程度:⭐️⭐️⭐
大于 1
且不能被除了 1
和它自己之外的任何数整除的整数叫作素数。
换句话说,n > 1
且不能被 1
和 n
之外的任何数整除的整数,被称为素数。
例如,5
是素数,由于它不能被 2
、3
和 4
整除,会产生余数。
写一个能够输出 2
到 n
之间的全部素数的代码。
当 n = 10
,结果输出 二、三、五、7
。
P.S. 代码应适用于任何 n
,而不是对任何固定值进行硬性调整。
在微信公众号「技术漫谈」后台回复 1-2-12
获取本题答案。
现代 JavaScript 教程:开源的现代 JavaScript 从入门到进阶的优质教程。React 官方文档推荐,与 MDN 并列的 JavaScript 学习教程。
在线免费阅读:zh.javascript.info
扫描下方二维码,关注微信公众号「技术漫谈」,订阅更多精彩内容。