多くの場合、アクションを繰り返す必要があります。
たとえば、リストから商品を次々に出力したり、1 から 10 までの数字ごとに同じコードを実行したりすることができます。
ループは、同じコードを複数回繰り返す方法です。
for…of ループと for…in ループ
上級読者向けのちょっとしたお知らせです。
この記事では、基本的なループ ( while
、 do..while
、およびfor(..;..;..)
のみを取り上げます。
他のタイプのループを探してこの記事にアクセスした場合は、次のヒントを参照してください。
オブジェクトのプロパティをループするには、「for…in」を参照してください。
配列および反復可能オブジェクトのループについては、for…of および iterables を参照してください。
それ以外の場合は、読み続けてください。
while
ループの構文は次のとおりです。
while (条件) { // コード // いわゆる「ループ本体」 }
condition
が真である間、ループ本体のcode
が実行されます。
たとえば、以下のループはi < 3
の場合にi
出力します。
i = 0 とします。 while (i < 3) { // 0、次に 1、次に 2 を表示します アラート( i ); i++; }
ループ本体の 1 回の実行は反復と呼ばれます。上の例のループは 3 回繰り返します。
上記の例にi++
が欠落している場合、ループは (理論上は) 永久に繰り返されます。実際には、ブラウザーにはそのようなループを停止する方法が用意されており、サーバーサイド JavaScript ではプロセスを強制終了できます。
比較だけでなく、任意の式または変数をループ条件にすることができます。条件はwhile
によって評価され、ブール値に変換されます。
たとえば、 while (i != 0)
短く記述する方法はwhile (i)
です。
i = 3 とします。 while (i) { // i が 0 になると条件が偽になり、ループが停止します アラート( i ); 私 - ; }
単一行の本文には中括弧は必要ありません
ループ本体にステートメントが 1 つある場合は、中括弧{…}
を省略できます。
i = 3 とします。 while (i) アラート (i--);
do..while
構文を使用して、条件チェックをループ本体の下に移動できます。
する { // ループ本体 while (条件);
このループは最初に本体を実行し、次に条件をチェックし、それが真実である限り何度も実行します。
例えば:
i = 0 とします。 する { アラート( i ); i++; while (i < 3);
この形式の構文は、条件が真であるかどうかに関係なく、ループの本体を少なくとも 1 回実行したい場合にのみ使用してください。通常は、他の形式 ( while(…) {…}
が推奨されます。
for
ループはより複雑ですが、最も一般的に使用されるループでもあります。
次のようになります。
for (開始; 条件; ステップ) { // ... ループ本体 ... }
これらの部分の意味を例を挙げて学びましょう。以下のループは、 i
に対して0
から3
まで (ただし、3 は含まれません) alert(i)
を実行します。
for (let i = 0; i < 3; i++) { // 0、次に 1、次に 2 を表示します アラート(i); }
for
ステートメントを部分ごとに調べてみましょう。
一部 | ||
---|---|---|
始める | let i = 0 | ループに入ると 1 回実行されます。 |
状態 | i < 3 | すべてのループ反復の前にチェックされます。 false の場合、ループは停止します。 |
体 | alert(i) | 条件が正しい間、何度でも実行します。 |
ステップ | i++ | 各反復で本体の後に実行されます。 |
一般的なループ アルゴリズムは次のように機能します。
実行の開始 → (if 条件 → ボディを実行し、ステップを実行) → (if 条件 → ボディを実行し、ステップを実行) → (if 条件 → ボディを実行し、ステップを実行) → ...
つまり、 begin
1 回実行され、その後反復されます。各condition
テストの後、 body
とstep
が実行されます。
ループを初めて使用する場合は、例に戻って、それがどのように段階的に実行されるかを紙の上で再現すると役立ちます。
私たちの場合、まさに次のことが起こります。
// for (let i = 0; i < 3; i++) alter(i) // 実行開始 i = 0 とします // if 条件 → 本体を実行してステップを実行 if (i < 3) { アラート(i); i++ } // if 条件 → 本体を実行してステップを実行 if (i < 3) { アラート(i); i++ } // if 条件 → 本体を実行してステップを実行 if (i < 3) { アラート(i); i++ } // ...終了、今は i == 3 なので
インライン変数宣言
ここでは、「カウンタ」変数i
がループ内で宣言されています。これは「インライン」変数宣言と呼ばれます。このような変数はループ内でのみ表示されます。
for (i = 0; i < 3; i++) { アラート(i); // 0、1、2 } アラート(i); // エラー、そのような変数はありません
変数を定義する代わりに、既存の変数を使用することもできます。
i = 0 とします。 for (i = 0; i < 3; i++) { // 既存の変数を使用します アラート(i); // 0、1、2 } アラート(i); // 3、ループの外で宣言されているため表示されます
for
のどの部分もスキップできます。
たとえば、ループの開始時に何もする必要がない場合は、 begin
省略できます。
ここのように:
i = 0 とします。 // i はすでに宣言され、割り当てられています for (; i < 3; i++) { // 「begin」は必要ありません アラート( i ); // 0、1、2 }
step
部分を削除することもできます。
i = 0 とします。 for (; i < 3;) { アラート( i++ ); }
これにより、ループはwhile (i < 3)
と同じになります。
実際にすべてを削除して、無限ループを作成することができます。
のために (;;) { // 制限なく繰り返します }
2 つはセミコロンfor
ことに注意してください;
存在する必要があります。そうしないと、構文エラーが発生します。
通常、ループは条件が偽になると終了します。
ただし、特別なbreak
ディレクティブを使用していつでも強制的に終了できます。
たとえば、以下のループはユーザーに一連の数字を要求し、数字が入力されない場合は「中断」します。
合計 = 0 とします。 while (true) { let value = +prompt("数値を入力してください", ''); if (!value) ブレーク; // (*) 合計 += 値; } alert( '合計: ' + 合計 );
ユーザーが空行を入力するか入力をキャンセルすると、 break
ディレクティブは行(*)
でアクティブになります。ループを直ちに停止し、ループ後の最初の行に制御を渡します。つまり、 alert
。
「無限ループ + 必要に応じてbreak
」の組み合わせは、ループの状態をループの最初や最後ではなく、途中、またはループ本体の複数の場所でチェックする必要がある状況に最適です。
continue
ディレクティブは、 break
の「軽量バージョン」です。ループ全体が停止するわけではありません。代わりに、現在の反復を停止し、ループに新しい反復を強制的に開始します (条件が許せば)。
現在の反復が終了し、次の反復に進みたい場合に使用できます。
以下のループは、奇数の値のみを出力するためにcontinue
を使用します。
for (i = 0; i < 10; i++) { // true の場合、本文の残りの部分をスキップします if (i % 2 == 0) 続行; アラート(i); // 1、次に 3、5、7、9 }
i
の値が偶数の場合、 continue
ディレクティブは本体の実行を停止し、制御をfor
の次の反復 (次の番号で) に渡します。したがって、 alert
奇数の値に対してのみ呼び出されます。
continue
ディレクティブはネストを減らすのに役立ちます
奇数の値を示すループは次のようになります。
for (i = 0; i < 10; i++) { if (i % 2) { アラート( i ); } }
技術的な観点から見ると、これは上記の例と同じです。確かに、 continue
使用する代わりにコードをif
ブロックでラップすることもできます。
ただし副作用として、これによりもう 1 レベルのネスト (中括弧内のalert
呼び出し) が作成されました。 if
内のコードが数行より長い場合、全体の読みやすさが低下する可能性があります。
break/continue
。
式ではない構文構成要素は三項演算子?
とともに使用できないことに注意してください。 。特に、 break/continue
などのディレクティブはここでは許可されません。
たとえば、次のコードを取るとします。
if (i > 5) { アラート(i); } それ以外 { 続く; }
…疑問符を使用して書き直します。
(i > 5) ?アラート(i) : 続行します。 // ここでは続行は許可されていません
…動作が停止します。構文エラーがあります。
これは、疑問符演算子?
を使用しないもう 1 つの理由です。 if
の代わりに。
場合によっては、複数のネストされたループから一度に抜け出す必要があります。
たとえば、以下のコードでは、 i
とj
ループし、 (0,0)
から(2,2)
までの座標(i, j)
を要求します。
for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { let input = prompt(`座標 (${i},${j}) の値`, ''); // ここから終了して完了する場合はどうすればよいでしょうか (下記)。 } } アラート('完了!');
ユーザーが入力をキャンセルした場合にプロセスを停止する方法が必要です。
input
後の通常のbreak
では、内側のループのみがブレークされます。それだけでは十分ではありません。ラベルの皆さん、助けに来てください!
ラベルは、ループの前にコロンが付いた識別子です。
ラベル名: for (...) { ... }
以下のループ内のbreak <labelName>
ステートメントは、ラベルに分岐します。
外側: for (let i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { let input = prompt(`座標 (${i},${j}) の値`, ''); // 空の文字列またはキャンセルされた場合は、両方のループから抜け出します。 if (!input) ブレークアウター; // (*) // 値を使って何かを行う... } } アラート('完了!');
上記のコードでは、 break outer
outer
という名前のラベルを上方に検索し、そのループから抜け出します。
したがって、コントロールは(*)
からalert('Done!')
に直接進みます。
ラベルを別の行に移動することもできます。
外側: for (let i = 0; i < 3; i++) { ... }
continue
ディレクティブはラベルと一緒に使用することもできます。この場合、コードの実行はラベル付きループの次の反復にジャンプします。
ラベルではどこにも「ジャンプ」することはできません
ラベルを使用すると、コード内の任意の場所にジャンプできなくなります。
たとえば、次のようなことは不可能です。
ラベルを破る; // 下のラベルにジャンプします (機能しません) ラベル: (...) 用
break
ディレクティブはコード ブロック内に存在する必要があります。技術的には、ラベル付きのコード ブロックはどれでも機能します。例:
ラベル: { // ... ラベルを破る; // 動作します // ... }
…ただし、上記の例で見たように、時間の 99.9% のbreak
はループ内で使用されます。
continue
ループ内からのみ可能です。
3 種類のループについて説明しました。
while
– 条件は各反復の前にチェックされます。
do..while
– 各反復後に条件がチェックされます。
for (;;)
– 各反復の前に条件がチェックされ、追加の設定が利用可能です。
「無限」ループを作成するには、通常、 while(true)
構造が使用されます。このようなループは、他のループと同様に、 break
ディレクティブで停止できます。
現在の反復では何もしたくなく、次の反復に進みたい場合は、 continue
ディレクティブを使用できます。
ループの前にラベルをbreak/continue
サポートします。ラベルは、 break/continue
ネストされたループをエスケープして外側のループに進む唯一の方法です。
重要性: 3
このコードによってアラートされる最後の値は何ですか?なぜ?
i = 3 とします。 一方 (i) { アラート(i--); }
答え: 1
.
i = 3 とします。 一方 (i) { アラート(i--); }
ループを繰り返すたびにi
1
ずつ減少します。 while(i)
チェックは、 i = 0
のときにループを停止します。
したがって、ループのステップは次のシーケンスを形成します (「ループ展開」)。
i = 3 とします。 アラート(i--); // 3 を表示し、i を 2 に減らします alert(i--) // 2 を表示し、i を 1 に減らします alert(i--) // 1 を表示し、i を 0 に減らします // 完了、while(i) チェックによりループが停止します
重要度: 4
ループの反復ごとに、出力される値を書き留めて、それを解と比較します。
両方のループが同じ値をalert
か?
接頭辞の形式は++i
。
i = 0 とします。 while (++i < 5) アラート( i );
i++
形式の接尾辞
i = 0 とします。 while (i++ < 5) アラート( i );
このタスクでは、後置/接頭辞形式を比較に使用すると、どのように異なる結果が得られるかを示します。
1から4まで
i = 0 とします。 while (++i < 5) アラート( i );
++i
最初にi
をインクリメントしてから新しい値を返すため、最初の値はi = 1
です。したがって、最初の比較は1 < 5
であり、 alert
1
表示されます。
次に、 2, 3, 4…
と続き、値が次々に表示されます。 ++
が変数の前にあるため、比較では常に増分値が使用されます。
最後に、 i = 4
が5
に増分され、 while(5 < 5)
の比較が失敗し、ループが停止します。したがって、 5
表示されません。
1から5まで
i = 0 とします。 while (i++ < 5) アラート( i );
最初の値はやはりi = 1
です。 i++
の後置形式はi
をインクリメントしてから古い値を返すため、比較i++ < 5
では ( ++i < 5
とは対照的に) i = 0
が使用されます。
ただし、 alert
コールは別です。これは、インクリメントと比較の後に実行される別のステートメントです。したがって、現在のi = 1
を取得します。
次に2, 3, 4…
と続きます。
i = 4
で止めましょう。接頭辞形式++i
それをインクリメントし、比較で5
使用します。しかし、ここでは後置形式i++
があります。したがって、 i
5
にインクリメントしますが、古い値を返します。したがって、比較は実際にはwhile(4 < 5)
– true となり、制御はalert
に進みます。
次のステップではwhile(5 < 5)
が false になるため、値i = 5
が最後の値になります。
重要度: 4
各ループについて、どの値が表示されるかを書き留めます。次に、答えと比較します。
両方のループが同じ値alert
か?
後置形式:
for (let i = 0; i < 5; i++)alert( i );
接頭辞の形式は次のとおりです。
for (let i = 0; i < 5; ++i)alert( i );
答えは、どちらの場合も0
~ 4
です。
for (let i = 0; i < 5; ++i)alert( i ); for (let i = 0; i < 5; i++)alert( i );
これは、 for
のアルゴリズムから簡単に推測できます。
すべての前 (開始) にi = 0
で 1 回実行します。
条件i < 5
を確認してください
true
の場合 – ループ本体のalert(i)
を実行してからi++
実行します。
インクリメントi++
は条件チェック (2) から分離されています。それは単なる別の発言です。
インクリメントによって返される値はここでは使用されないため、 i++
と++i
の間に違いはありません。
重要度: 5
for
ループを使用して、 2
~ 10
の偶数を出力します。
デモを実行する
for (let i = 2; i <= 10; i++) { if (i % 2 == 0) { アラート( i ); } }
ここでは「モジュロ」演算子%
使用して剰余を取得し、均等性をチェックします。
重要度: 5
for ループの動作を変更せずに、 for
ループをwhile
に変更してコードを書き直します (出力は同じままになるはずです)。
for (i = 0; i < 3; i++) { alert( `number ${i}!` ); }
i = 0 とします。 while (i < 3) { alert( `number ${i}!` ); i++; }
重要度: 5
100
より大きい数値の入力を求めるループを作成します。訪問者が別の番号を入力した場合は、再度入力するよう求めます。
このループは、訪問者が100
を超える数値を入力するか、入力をキャンセルするか空の行を入力するまで、数値を要求する必要があります。
ここでは、訪問者は数字のみを入力すると仮定できます。このタスクでは、数値以外の入力に対する特別な処理を実装する必要はありません。
デモを実行する
数字をあげましょう。 する { num = プロンプト("100 より大きい数値を入力してください?", 0); while (num <= 100 && num);
両方のチェックが正しい間、ループdo..while
が繰り返されます。
num <= 100
のチェック – つまり、入力された値がまだ100
以下であることを意味します。
&& num
がnull
または空の文字列の場合、チェック&& num
false になります。その後、 while
ループも停止します。
PS num
がnull
の場合、 num <= 100
はtrue
となるため、2 番目のチェックがなければ、ユーザーが [CANCEL] をクリックしてもループは停止しません。両方のチェックが必要です。
重要性: 3
1
より大きい整数は、 1
とそれ自身以外の何によっても剰余なしで割り切れない場合、素数と呼ばれます。
言い換えれば、 n > 1
1
とn
以外の何によっても均等に割り切れない場合、それは素数になります。
たとえば、 5
素数です。これは、剰余なしで2
、 3
、 4
で割ることができないためです。
2
からn
までの素数を出力するコードを書きます。
n = 10
の場合、結果は2,3,5,7
になります。
PS コードは、固定値に合わせてハードチューニングするのではなく、任意のn
に対して機能する必要があります。
このタスクには多くのアルゴリズムがあります。
ネストされたループを使用してみましょう。
区間内の各 i について { 1..i からの約数があるかどうかを確認してください はいの場合 => 値は素数ではありません いいえの場合 => 値が素数である場合は、それを表示します }
ラベルを使用したコード:
n = 10 とします。 次のプライム: for (let i = 2; i <= n; i++) { // 各 i... for (let j = 2; j < i; j++) { // 除数を探します。 if (i % j == 0) nextPrime を続行します。 // 素数ではないので、次に進みます。 } アラート( i ); // 素数 }
最適化できる余地はたくさんあります。たとえば、 2
からi
の平方根までの約数を探すことができます。しかし、とにかく、大きな間隔で本当に効率的にしたい場合は、アプローチを変更し、高度な数学と二次ふるい、一般数体ふるいなどの複雑なアルゴリズムに依存する必要があります。