JavaScript超入門④ ループと配列を使おう
while、for、for...of、配列、push、break、continueを使い、複数の値を順番に処理します。
1人へあいさつするコードは書けても、クラス全員に同じ処理をしたいときはどうすればよいのでしょうか。人数分コピーするのは、さすがに大変ですよね。
今回はループで同じ処理を繰り返し、配列で複数の値をまとめます。「何回動くか」「どの値を今見ているか」を追えるようになりましょう。
コード例は別々に実行してください。同じconst名の再宣言で困ったら、練習ページを再読み込みします。
1. whileは、毎回条件を確認する
let count = 1;
while (count <= 3) {
console.log(count);
count++;
}
console.log(`終了時のcountは${count}です`);
1
2
3
終了時のcountは4です
count++は、この使い方ではcount = count + 1と同じく1増やす操作です。
| 条件を見るときのcount | 判定 | その後 |
|---|---|---|
| 1 | true | 1を表示して2へ |
| 2 | true | 2を表示して3へ |
| 3 | true | 3を表示して4へ |
| 4 | false | 本体へ入らず終了 |
countを最初から4にすると、ループ内は一度も動きません。whileは、条件に合わなければ0回で終わる仕組みです。
更新を忘れると、終わらない
countを増やす行を消すと、ずっと1のままです。条件がfalseにならず、表示を繰り返す無限ループになります。
ブラウザの画面が固まる原因にもなるため、実行前に「どの値が変わって、どこで止まるか」を確認しましょう。誤って動かしたら、開発者ツールの停止操作や練習用タブを閉じるなどして中断します。
2. forは回数の情報をまとめられる
for (let i = 1; i <= 3; i++) {
console.log(i);
}
表示は1、2、3です。丸かっこの中は次の3つです。
let i = 1:最初の1回だけ準備するi <= 3:本体の前に条件を調べるi++:本体が終わったら更新する
実際には「準備 → 条件 → 本体 → 更新 → 条件」の順に動きます。コード上の並びだけを見て、更新が表示より前だと思わないようにしてください。
iを0から始めるなら、3回動かす条件はi < 3です。0、1、2の3つになります。i <= 3なら4回です。MDNのループの説明でも実行順を確認できます。
3. 配列で、複数の値を順番に保存する
const scores = [80, 95, 70];
console.log(scores[0]);
console.log(scores[2]);
console.log(scores.length);
結果は80、70、3です。
[80, 95, 70]が配列です。中の値を要素、位置の番号を添字(インデックス)と呼びます。
| 添字 | 0 | 1 | 2 |
|---|---|---|---|
| 点数 | 80 | 95 | 70 |
最初は0、最後は要素数-1です。今回のscores[3]は存在しないのでundefinedになります。CやC++とは違い、この読み方がただちに同じ種類の未定義動作になるわけではありませんが、計算に使うとNaNなど予想外の結果につながります。
lengthは今回の配列の個数
今回のように隙間なく作った配列なら、lengthは要素数です。JavaScriptでは途中の番号を飛ばした疎な配列も作れるので、厳密にはlengthが実際に値のある場所の数と一致しない場合があります。
初めはscores[10] = 50;のような飛び飛びの追加を避け、次のpushを使いましょう。
4. pushで追加し、constでも中身を変更する
const scores = [80, 95];
scores.push(70);
console.log(scores.length);
console.log(scores[2]);
結果は3と70です。pushは配列の末尾へ要素を追加します。
「constなのに変更してよいの?」という疑問が出るかもしれません。constが禁止するのは、scoresへ別の配列を再代入することです。今ある配列の中身の変更はできます。
scores = [];は再代入なのでエラーですが、scores[0] = 85;やscores.push(70);はできます。MDNのArrayに、配列の操作がまとまっています。
5. for…ofは、値を1つずつ取り出す
const names = ["Aoi", "Ren", "Mio"];
for (const name of names) {
console.log(`こんにちは、${name}さん`);
}
Aoi、Ren、Mioの順にあいさつします。nameには添字0、1、2ではなく、各要素の値が入ります。
添字が不要ならfor…ofが読みやすくなります。番号も必要なときは、普通のforでnames[i]を使う方法があります。
合計は、ループの外に置く
const scores = [80, 95, 70];
let total = 0;
for (const score of scores) {
total += score;
}
console.log(total);
totalは80 → 175 → 245と増えます。total += scoreは現在の合計へ点数を足す書き方です。
let total = 0;をループ内へ移すと、毎回0から計算してしまいます。次の回にも覚えておきたい値は外で用意します。
また、数値のscoreを書き換えても元の配列の要素が自動で変わるわけではありません。オブジェクトが入った配列の扱いは第6回で区別します。
6. breakとcontinueを使い分ける
for (let i = 1; i <= 8; i++) {
if (i === 6) {
break;
}
if (i === 3) {
continue;
}
console.log(i);
}
表示は1、2、4、5です。
- 3の回はcontinueで表示を飛ばし、次の更新へ進む
- 6の回はbreakでループそのものを終える
- 7、8の回へは進まない
forでcontinueしてもi++は実行されます。一方whileで更新を本体の後ろへ置くと、continueで更新を飛ばす場合があります。「更新行は書いたのに止まらない」ときは、そこを通っているか確認します。
forEachでbreakしようとしない
配列にはforEachという別の処理方法もありますが、普通のbreakで外へ抜ける使い方はできません。途中で終了したいなら、まずforやfor…ofを使う方が分かりやすいでしょう。
また、回しながら同じ配列へ次々pushすると、処理対象が増え続ける場合があります。入力の配列を変更せず、結果を別の配列へ集める設計から始めると整理しやすくなります。
7. 練習:合計と平均を出そう
点数[72, 88, 95, 65]の合計と平均をfor…ofで求めてください。空の配列なら、平均を計算しないようにします。
模範解答
const scores = [72, 88, 95, 65];
if (scores.length === 0) {
console.log("点数がありません");
} else {
let total = 0;
for (const score of scores) {
total += score;
}
const average = total / scores.length;
console.log(`合計は${total}点です`);
console.log(`平均は${average}点です`);
}
合計は320点です
平均は80点です
解説
合計は72 → 160 → 255 → 320と変わり、4個で割って80です。毎回変わるtotalはlet、最後に決まるaverageはconstにしています。
空の配列なら先に表示して終えるため、0で割ってNaNになる計算をしません。今回の配列には有効な数値だけを入れています。フォームから作る場合は、追加前の型変換と範囲チェックも必要です。
確認として1個だけの[90]なら合計90、平均90。[]なら「点数がありません」が答えになります。
次の一歩
ループを読むときは、「今の番号」「今の要素」「ここまでの結果」の3つを分けましょう。複雑に見える処理も、最初の2〜3回だけ表にすると追いやすくなります。