現代 JavaScript 教程 — while 和 for 循環

循環:while 和 for

咱們常常須要重複執行一些操做。javascript

例如,咱們須要將列表中的商品逐個輸出,或者運行相同的代碼將數字 1 到 10 逐個輸出。html

循環 是一種重複運行同一代碼的方法。java

"while" 循環

while 循環的語法以下:react

while (condition) {
  // 代碼
  // 所謂的「循環體」 
}
複製代碼

conditiontrue 時,執行循環體的 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 語法能夠將條件檢查移至循環體 下面

do {
  // 循環體
} while (condition);
複製代碼

循環首先執行循環體,而後檢查條件,當條件爲真時,重複執行循環體。

例如:

let i = 0;
do {
  alert( i );
  i++;
} while (i < 3);
複製代碼

這種形式的語法不多使用,除非你但願無論條件是否爲真,循環體 至少執行一次。一般咱們更傾向於使用另外一個形式:while(…) {…}

"for" 循環

for 循環更加複雜,但它是最常使用的循環形式。

for 循環看起來就像這樣:

for (begin; condition; step) {
  // ……循環體……
}
複製代碼

咱們經過示例來了解一下這三個部分的含義。下述循環從 i 等於 03(但不包括 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 後,執行 bodystep

若是你這是第一次接觸循環,那麼回到這個例子,在一張紙上重現它逐步運行的過程,可能會對你有所幫助。

如下是在這個示例中發生的事:

// 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 僅被奇數值調用。


continue 指令利於減小嵌套:

顯示奇數的循環能夠像下面這樣:

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 的另外一個緣由。


break/continue 標籤

有時候咱們須要從一次從多層嵌套的循環中跳出來。

例如,下述代碼中咱們的循環使用了 ij,從 (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 跳出嵌套循環以轉到外部的惟一方法。

做業題

先本身作題目再看答案。

1. 最後一次循環的值

重要程度:⭐️⭐️⭐

此代碼最後一次 alert 值是多少?爲何?

let i = 3;

while (i) {
  alert( i-- );
}
複製代碼

2. while 循環顯示哪些值?

重要程度:⭐️⭐️⭐️⭐

對於每次循環,寫出你認爲會顯示的值,而後與答案進行比較。

如下兩個循環的 alert 值是否相同?

  1. 前綴形式 ++i:

    let i = 0;
    while (++i < 5) alert( i );
    複製代碼
  2. 後綴形式 i++

    let i = 0;
    while (i++ < 5) alert( i ); 複製代碼

3. "for" 循環顯示哪些值?

重要程度:⭐️⭐️⭐️⭐

對於每次循環,寫下它將顯示的值。而後與答案進行比較。

兩次循環 alert 值是否相同?

  1. 後綴形式:

    for (let i = 0; i < 5; i++) alert( i );
    複製代碼
  2. 前綴形式:

    for (let i = 0; i < 5; ++i) alert( i );
    複製代碼

4. 使用 for 循環輸出偶數

重要程度:⭐️⭐️⭐️⭐️⭐️

使用 for 循環輸出從 210 的偶數。

5. 用 "while" 替換 "for"

重要程度:⭐️⭐️⭐️⭐️⭐️

重寫代碼,在保證不改變其行爲的狀況下,將 for 循環更改成 while(輸出應保持不變)。

for (let i = 0; i < 3; i++) {
  alert( `number ${i}!` );
}
複製代碼

6. 重複輸入,直到正確爲止

重要程度:⭐️⭐️⭐️⭐️⭐️

編寫一個提示用戶輸入大於 100 的數字的循環。若是用戶輸入其餘數值 —— 請他從新輸入。

循環一直在請求一個數字,直到用戶輸入了一個大於 100 的數字,取消輸入或輸入了一個空行爲止。

在這咱們假設用戶只會輸入數字。在本題目中,不須要對非數值輸入進行特殊處理。

7. 輸出素數(prime)

重要程度:⭐️⭐️⭐

大於 1 且不能被除了 1 和它自己之外的任何數整除的整數叫作素數

換句話說,n > 1 且不能被 1n 之外的任何數整除的整數,被稱爲素數。

例如,5 是素數,由於它不能被 234 整除,會產生餘數。

寫一個能夠輸出 2n 之間的全部素數的代碼。

n = 10,結果輸出 二、三、五、7

P.S. 代碼應適用於任何 n,而不是對任何固定值進行硬性調整。

答案:

在微信公衆號「技術漫談」後臺回覆 1-2-12 獲取本題答案。


現代 JavaScript 教程:開源的現代 JavaScript 從入門到進階的優質教程。React 官方文檔推薦,與 MDN 並列的 JavaScript 學習教程

在線免費閱讀:zh.javascript.info


掃描下方二維碼,關注微信公衆號「技術漫談」,訂閱更多精彩內容。

相關文章
相關標籤/搜索