Skip to content
This page has been auto-translated and may contain errors.View in English

ループ

docs.scrimba.com

1から100までの数字を表示したり、単語の各文字にあいさつをしたり、答えが正しくなるまで繰り返し質問したいとします。同じ行を何百回も書くことはできますが、それは入力が面倒で、変更はさらに大変です。ループは、JavaScriptにコードを繰り返し実行させる方法です。作業を1回書いて、言語に繰り返させます。この章では、最もよく使用される3つのループをカバーします:forwhilefor...ofです。

for ループ

**for ループ**は、繰り返す回数がわかっているときに使用します。カウント機能が組み込まれています。0から4までの数字を表示する例です:

js
for (let i = 0; i < 5; i++) {
  console.log(i);
}
// 0
// 1
// 2
// 3
// 4

括弧内の部分は、セミコロンで区切られた3つの部分があります:

  • let i = 0開始です:iというカウンターを作成して0に設定します。
  • i < 5条件です:この条件が真である限り、ループは続きます。
  • i++ステップです:各パスの後、iに1を加えます(i++i = i + 1の短縮形です)。

つまり、ループはiを0で開始し、i < 5をチェックし、中括弧内のコードを実行してから1を加えてもう一度チェックします。iが5に達すると条件は偽になり、ループは停止します。

**for ループ**は、繰り返し回数があらかじめわかっている場合に適しています。3つの部分をヘッダーに詰め込み、順序どおりに実行します:

js
for (let i = 0; i < 5; i++) {
  console.log(`pass number ${i}`);
}
// pass number 0
// pass number 1
// pass number 2
// pass number 3
// pass number 4

ヘッダーを左から右に読むと:let i = 0イニシャライザーで、他の何よりも前に1回実行されます。i < 5条件で、すべてのパスの前にチェックされ、ループは真である限りのみ実行されます。i++ステップで、各パスの後に実行されます。カウンターiは通常の変数なので、ループ内で読み取ることができます。これが、ループとカウントが一緒に機能する理由です。

規則ではなく慣例として、カウンターは0から開始します。JavaScriptではほぼ至る所で0からカウントするのが見られ、配列が項目に番号を付ける方法と一致するため、早い段階から慣れておく価値があります。

**for ループ**は、1つのヘッダーにカウント繰り返しの全体像をエンコードします:イニシャライザー、条件、ステップで、セミコロンで区切られています。

js
for (let i = 0; i < 5; i++) {
  console.log(`pass number ${i}`);
}
// pass number 0
// pass number 1
// pass number 2
// pass number 3
// pass number 4

順序は正確で、内在化する価値があります:イニシャライザーが1回実行され、その後条件がテストされ、真である場合のみ本体が実行され、その後ステップが実行され、条件に戻ります。この順序により、条件が最初のパスの前にチェックされるため、条件が最初から偽であるループは本体をまったく実行しません。

カウンターにはconstではなくletを使用します。ステップはそれを毎回再割り当てするためです。ヘッダーでiを宣言すると、それがループの範囲内に限定されるため、周囲のコードに漏れず、ループをネストしたり連続して複数書いたりするときにカウンターが衝突するのを防ぎます。1ではなく0からカウントするのはほぼ普遍的な慣例で、配列がその要素にインデックスを付ける方法に直接マップされるため、この習慣はすぐにデータをループするときに役立ちます。

Junofor ループforループは固定回数繰り返され、カウント機能が組み込まれています。ヘッダーには3つの部分があります:let i = 0のような開始、i < 5のような条件でループを続け、i++のようなステップでそれを進めます。条件が偽になると、ループは停止します。
Junofor ループ カウントがあらかじめわかっている場合は、forを選んでください。ヘッダーはイニシャライザーを1回実行し、すべてのパスの前に条件をチェックし、各パスの後にステップを実行します。0からカウントするのは慣例で、配列が項目に番号を付ける方法と一致するため、今からそれに合わせてください。
Junofor ループ ヘッダーの順序は固定です:1回初期化し、条件をテストし、本体を実行し、ステップを実行し、繰り返します。そのため、条件が最初から偽であると、本体全体がスキップされます。カウンターにはletを使用してステップが再割り当てできるようにし、ヘッダーで宣言してループの範囲内に留めてください。

while ループ

時には繰り返す回数がわからず、真のままであるべき条件だけがわかることがあります。それが**while ループ**の用途です。条件が成り立つ限り実行し続けます:

js
let count = 3;
while (count > 0) {
  console.log(count);
  count = count - 1;
}
console.log("Go");
// 3
// 2
// 1
// Go

ループはcount > 0をチェックし、コードを実行してから、もう一度チェックします。ループ内の何かがcountを変更することに注目してください。そうすることで条件は最終的に偽になり、ループは停止します。内部で条件を偽にするものがない場合、ループは永遠に実行されます。これは無限ループで、プログラムがフリーズするため、常に条件が変わる可能性があることを確認してください。

**while ループ**は、条件が真のままである限り繰り返され、組み込みのカウンターやステップはありません。繰り返し回数があらかじめわかっていない場合はこれが正しいツールで、わかっている場合はforループが正しいツールです。

js
let attempts = 0;
let password = "";
while (password !== "letmein") {
  password = "letmein"; // 実際のプロンプトの代替
  attempts = attempts + 1;
}
console.log(`Unlocked after ${attempts} attempt(s)`);
// Unlocked after 1 attempt(s)

条件(password !== "letmein")は条件の比較演算子に依存し、ループは偽になるまで実行されます。問題は、条件が偽になることを強制するものがないことです:ループが依存する何かを変更する必要があります。条件が決して偽にならない while ループは永遠に実行されます。これは無限ループで、プログラムをハングさせます。

**while ループ**は一般的な形です:条件が真のままである限り繰り返され、カウント(ある場合)は完全にあなたに任されます。反復回数が固定されていない場合、たとえば入力が検証されるまでまたは値が閾値を超えるまで繰り返すときに選んでください。カウントがわかっている場合、forループはその意図をより明確に述べています。

js
let remaining = 100;
let steps = 0;
while (remaining > 0) {
  remaining = remaining - 15;
  steps = steps + 1;
}
console.log(`Emptied in ${steps} steps`);
// Emptied in 7 steps

尊重すべき失敗モードは無限ループです:whileは終了の構造的保証を与えないため、本体は条件を偽に向かわせる必要があります。ループをハングさせる3つのことがあります:条件が更新されない、更新が間違った方向に進む、条件が満たされるのではなく踏み越えられる場合です(上記でremaining === 0を使用すると、remainingが正確に0ではなく負の数に着地するため、ミスします)。すべての while ループは、条件を偽に向かわせるある行が必要です。=== 0のような正確な値ではなく、> 0のような範囲テストを優先してください。これにより、オーバーシュートするステップでもループが終了します。

Junowhile ループwhileループは条件が真である限り繰り返され、組み込みのカウンターがありません。繰り返し回数があらかじめわからない場合に使用してください。常にループ内の何かを変更して条件を偽にできるようにするか、プログラムをフリーズさせる無限ループが発生します。
Junowhile ループ 繰り返し回数が不明な場合はwhileを選び、固定である場合はforを選んでください。本体は条件がテストするものを変更する必要があります。そうしないと偽になることはありません。それが無限ループで、whileを書くたびに注視すべき間違いです。
Junowhile ループwhileは終了を保証しないため、本体は条件を偽に向かわせる必要があります。3つのハング方法:条件が更新されない、間違った方向に進む、踏み越えられる。=== 0のような正確な値ではなく、> 0のような範囲テストを優先してください。これにより、オーバーシュートするステップでもループが終了します。

for...of で文字列をループする

forループとwhileループはカウンターで数を扱いますが、通常は何かの各項目を直接訪問したいことがあります。**for...of**がそれを行います。ここで単語の各文字を歩きます:

js
for (const char of "hello") {
  console.log(char);
}
// h
// e
// l
// l
// o

これを「単語の各文字について」と読んでください。各パスで、charは次の文字を保持し、カウンターや条件に触れることはありません。各項目を順番に見たいだけの場合、forループよりも整理されています。

for...ofは主に配列で使用します。配列は次の章で学ぶ値のリストです。文字列は文字の順序であり、for...ofはそれをまさにそのように扱うため、ループする最初の良いものです。

**for...of**はシーケンスの項目を直接反復処理し、管理するカウンターや条件がなく、各値を順番に渡します:

js
let vowels = 0;
for (const char of "javascript") {
  if (char === "a" || char === "i") {
    vowels = vowels + 1;
  }
}
console.log(`Found ${vowels} of those vowels`);
// Found 3 of those vowels

ここでconst charを使用することは意図的です:各パスは新しいcharを作成し、読み取るだけで再割り当てしないため、constが適切で意図を示します。for...ofループは、カウンターループの手動ブックキープを可読性と交換し、手動でインデックスを付けないため、オフバイワン誤りの全クラスを削除します。

文字列はループする自然な最初のシーケンスですが、本当の主力は配列です。配列に出会うと、for...ofはその内容を歩く整理された直接的な方法です。

**for...of**はシーケンスを要素ごとに反復処理し、インデックスを公開せずに各値を名前にバインドします。文字列に対して、それは文字を生成します:

js
let shout = "";
for (const char of "loops") {
  shout = shout + char.toUpperCase();
}
console.log(shout);
// LOOPS

constでループ変数をバインドします:for...ofは各パスで新しいバインディングを作成するため、何も再割り当てする必要はなく、constは値が本体内で読み取り専用であることを文書化します。カウンターループに対する利点は、インデックスを書かないため、構造によってオフバイワンエラーを回避することです。

これが最も重要なのは配列です。各要素を訪問する場合、for...ofはカウントforループより整理して読み取られ、意図を直接述べます。ただし、コレクションを新しいものに変換する場合、配列反復メソッドは通常、手動ループを完全に置き換え、それらは独自の章でカバーされています。

break と continue

2つのキーワードは、任意のループ内でより細かい制御を提供します。breakはループを直ちに停止し、その後のコードに移動します。continueは現在のパスの残りをスキップし、次のパスに直接ジャンプします。

js
for (let i = 0; i < 10; i++) {
  if (i === 3) {
    continue; // 3をスキップし、ループを続ける
  }
  if (i === 6) {
    break; // ループを完全に停止
  }
  console.log(i);
}
// 0
// 1
// 2
// 4
// 5

breakは、必要なものを見つけたら早期に停止し、無意味にスキャンし続けないようにするためのものです。continueは、本体の残りをifの内部にネストすることなく、気にしないケースをスキップするためのものです。

オフバイワンエラーとインデックス境界

古典的なループバグはオフバイワンエラーです:1回多すぎるか1回少なすぎる実行です。これはカウンターの境界から来ています。長さ5の文字列は、位置0、1、2、3、および4に文字があるため、最後の有効な位置はlengthではなくlength - 1です。つまり、位置のカウンティングループがi < text.lengthを使用する理由です。i <= text.lengthではありません:

js
const text = "hello";
for (let i = 0; i < text.length; i++) {
  console.log(text[i]);
}
// h
// e
// l
// l
// o

i <= text.lengthと書くと、最後のパスは位置5に到達しますが、これは存在しないため、undefinedを生成します。0からカウントして<で長さまでは、すべての位置に正確に着地し、それ以上ではないパターンです。各項目が必要で、その位置ではない場合、for...ofは境界の質問を完全に回避します。これは、それを優先する理由です。

Junofor...of で文字列をループするfor...ofは各項目を直接訪問し、管理するカウンターや条件がありません。文字列では、各パスは次の文字を与えます。その後、配列で最もそれを使用しますが、文字列は文字の順序であるため、ループする整理された最初のものです。
Junofor...of で文字列をループするfor...ofは各値を順番に渡すため、カウンターと手動でインデックスを付けるときに来るオフバイワンリスクをスキップします。constでバインドします。各パスは読み取り専用です。文字列は良い開始ですが、配列はあなたがそれに出会うと、あなたがそれに頼るところです。
Junofor...of で文字列をループするfor...ofは各要素を新しいconstにバインドし、インデックスを公開しないため、構造によってオフバイワンバグを削除します。breakは早期に停止し、continueはパスをスキップします。コレクションを歩くだけではなく変換する場合、配列反復メソッドは通常、手動ループを置き換え、それらは独自の章を取得します。

ここからループがどこへ向かうか

ループは、自分自身を繰り返す必要をなくし、言語に繰り返させるための方法です。forループは既知の回数をカウントし、whileは条件が成り立つ限り繰り返され、for...ofはシーケンスの項目を直接歩きます。ここから持ち出すべき1つの習慣:すべてのループが終了できることを確認し、各項目が必要な場合はfor...ofを優先してください。

ループが重要な本当の理由は、使用するデータのほとんどがコレクションで来ることです。次の章では配列を紹介します。これは、常にループするリストで、その後配列メソッドは、データを変換しているときに手書きループを置き換えることが多いです。ループが依存する条件を研ぎ澄ましたい場合、条件は、ループが続く場合と停止する場合を決定する比較をカバーしています。