javascript 基本文法6

公開日: 2025/3/31

javascript 基本文法6

1. ループと反復処理


プログラミングにおいて、同じ処理を繰り返すために同じコードを繰り返し書く必要はありません。

ループやイテレータなどを使う事で反復処理として同じ処理を繰り返し実行できます。

また、for文などのような構文だけでなく、配列のメソッドを利用して反復処理を行う方法もあります。

1-1. while

while文は条件式がtrueであるならば、反復処理を行います。

while (条件式) {
    実行する文;
}

最初から条件式がfalseである場合は、何も実行せずwhile文は終了します。

 1.条件式の評価結果がtrueなら次のステップへ、falseなら終了

 2.実行する文を実行

 3.ステップ1へ戻る

xの値が10未満であるなら、コンソールへ繰り返しログが出力されます。

また、実行する文にて、xの値を増やし条件式がfalseとなります。

let x = 0;
console.log(`ループ開始前のxの値: ${x}`);
while (x < 10) {
    console.log(x);
    x += 1;
}
console.log(`ループ終了後のxの値: ${x}`);

ループ開始前のxの値: 0
0
1
2
3
4
5
6
7
8
9
ループ終了後のxの値: 10

実行する文の中で条件式がfalseとなるような処理を書かないと無限ループします。

JavaScriptには安全な反復処理の書き方があるため、while文は使う場面が限られています。

1-2. 無限ループ

反復処理を扱う際に、コードの書き間違いや条件式のミスなどから無限ループを引き起こしてしまう場合があります。

たとえば、次のコードは条件式の評価結果が常にtrueとなってしまうため、無限ループが発生してしまいます。

let i = 1;
// 条件式が常にtrueになるため、無限ループする
while (i > 0) {
    console.log(`${i}回目のループ`);
    i += 1;
}

無限ループが発生してしまったときは、スクリプトを停止してからコードを修正しましょう。


ほとんどのブラウザは無限ループが発生した際に、自動的にスクリプトの実行を停止する機能が含まれています。

また、ブラウザで該当のスクリプトを実行しているページ(タブ)またはブラウザそのものを閉じることで強制的に停止できます。

Node.jsで実行している場合はCtrl + Cを入力し、終了シグナルを送ることで強制的に停止できます。


無限ループが発生する原因のほとんどは条件式に関連する実装ミスです。 まずは条件式の確認をしましょう。

1-3. do-while文

do-while文はwhie文とほとんど同じですが実行順序が異なります。

do{
   実行する文;
}while(条件式);

 1.実行する文を実行

 2.条件式の評価結果がtrueなら次のステップへ、falseなら終了

 3.ステップ1へ戻る


while文とは異なり、必ず最初に実行する文に処理します。

そのため、最初から条件式を満たさない場合でも、初回の実行する文が処理され、コンソールへ1000と出力されます。

const x=1000;
do{
    console.log(1000);//=>1000
}while(1000<10);

1-4. for文

for文は繰り返す範囲を設定した反復処理を書くことができます。

for (初期化式; 条件式; 増分式) {
    実行する文;
}

for文の実行フローは次のようになります。

 1.初期化式で変数の宣言

 2.条件式の評価結果がtrueなら次のステップへ、falseなら終了

 3.実行する文を実行

 4.増分式で変数を更新

 5.ステップ2へ戻る

let total = 0; 
for (let i = 0; i < 10; i++) {
    total += i + 1;
}
console.log(total);

このコードは1から10までの合計を電卓で計算すればいいので、基本的に必要ありません。

 実用的なものを考えると、任意の数値の入った配列を受け取り、その合計を計算して返すという関数を実装すると良い感じになりそうです。


次のコードでは、任意の数値が入った配列を受け取り、その合計値を返す sum 関数を実装しています。

numbers配列に含まれている要素を先頭から順番に変数totalへ加算することで合計値を計算しています。

function sum(numbers) {
    let total = 0;
    for (let i = 0; i < numbers.length; i++) {
        total += numbers[i];
    }
    return total;
}

console.log(sum([1, 2, 3, 4, 5]));

15

JavaScriptの配列であるArrayオブジェクトには、反復処理のためのメソッドが備わっています。

1-5. 配列のforEachメソッド

配列にはforEachメソッドというfor文と同じように反復処理を行うメソッドがあります。

const array=[1,2,3];
array.forEach(currentValie=>{
    
})

JavaScriptでは、関数がファーストクラスであるため、その場で作った無名関数(名前のない関数)を引数として渡せます。


引数として渡される関数のことをコールバック関数と呼びます。

また、コールバック関数を引数として受け取る関数やメソッドのことを高階関数と呼びます。

const array=[1,2,3];
array.forEach(コールバック関数);

forEachメソッドのコールバック関数には、配列の要素が先頭から順番に渡されて実行されます。

つまり、コールバック関数の仮引数であるcurrentValueには、1から3の値が順番に渡されます。

const array=[1,2,3];
array.forEach(currentValue=>{
    console.log(currentValue);
});

1
2
3

for文の例と同じ数値の合計を返すsum 関数をforEachメソッドで実装した場合。

function sum(numbers) {
    let total = 0;
    numbers.forEach(num => {
        total += num;
    });
    return total;
}

sum([1, 2, 3, 4, 5]);

forEachはfor文の条件式に相当するものはなく、必ず配列のすべての要素を反復処理します。

変数iといった一時的な値を定義する必要がないため、シンプルに反復処理を書けます。

1-6. break文

break文は処理中の文から抜けて次の文へ移行する制御文です。

while、do-while、forの中で使い、処理中のループを抜けて次の文へ制御を移します。

while(true){
    break
}

switch文で出てきたものと同様で、処理中のループ文を終了できます。

次のコードでは配列の要素に1つでも偶数を含んでいるかを判定しています。

const numbers=[1,5,10,15,20];
let isEvenIncluded=false;
for(let i=0; i<numbers.length; i++){
    const num=numbers[i];
    if(num%2===0){
        isEvenIncluded=true;
        break;
    }
}
console.log(isEvenIncluded);

true

1つでも偶数があるかがわかればいいため、配列内から最初の偶数を見つけたらfor文での反復処理を終了します。

このような処理は、使い回せるように関数として実装するのが一般的です。

同様の処理をする isEvenIncluded 関数を実装してみます。

次のコードでは、break文が実行され、ループを抜けた後にreturn文で結果を返しています。

function isEven(num){
    return num%2===0;
    
}
function isEvenIncluded(numbers){
    let isEvenIncluded=false;
    for(let i=0; i<numbers.length; i++){
        const num=numbers[i];
        if(isEven(num)){
            isEvenIncluded=true;
            break;
        }
    }
    return isEvenIncluded;
}
const array=[1,5,10,15,20]
console.log(isEvenIncluded(array));

true

return文は現在の関数を終了させることができるため、次のように書くこともできます。

numbersに1つでも偶数が含まれていれば結果はtrueとなるため、偶数の値が見つかった時点でtrueを返しています。

function isEven(num) {
    return num % 2 === 0;
}
function isEvenIncluded(numbers) {
    for (let i = 0; i < numbers.length; i++) {
        const num = numbers[i];
&n

1-7. continue文

continue文は現在の反復処理を終了して、次の反復処理を行います。

continue文は、while、do-while、forの中で使うことができます。


たとえば、while文の処理中でcontinue文が実行されると、現在の反復処理はその時点で終了されます。

そして、次の反復処理で条件式を評価するところからループが再開されます。

while (条件式) {
    continue;
}

配列の中から偶数を集め、新しい配列を作り返しています。

偶数ではない場合、処理中のfor文をスキップしています。

function isEven(num) {
    return num % 2 === 0;
}
function filterEven(numbers) {
    const results = [];
    for (let i = 0; i < numbers.length; i++) {
        const num = numbers[i];
        if (!isEven(num)) {
            continue;
        }
      
        results.push(num);
    }
    return results;
}
const array = [1, 5, 10, 15, 20];
console.log(filterEven(array));

[ 10, 20 ]

次のようにcontinue文を使わずに「偶数ならresultsへ追加する」という書き方も可能です。

if (isEven(number)) {
    results.push(number);
}

1-8. for...in文

for...in文はオブジェクトのプロパティに対して、反復処理を行います。

for (プロパティ in オブジェクト) {
    実行する文;
}

次のコードではobjのプロパティ名をkey変数に代入して反復処理をしています。

objには、3つのプロパティ名があるため3回繰り返されます (ループのたびに毎回新しいブロックを作成しているため、ループごとに定義する変数keyは再定義エラーになりません。

const obj = {
    "a": 1,
    "b": 2,
    "c": 3
};
for (const key in obj) {
    const value = obj[key];
    console.log(`key:${key}, value:${value}`);
}

key:a, value:1
key:b, value:2
key:c, value:3

オブジェクトに対する反復処理のためにfor...in文は有用に見えますが、多くの問題があります。


JavaScriptでは、オブジェクトは何らかのオブジェクトを継承しています。

for...in文は、対象となるオブジェクトのプロパティを列挙する場合に、親オブジェクトまで列挙可能なものがあるかを探索して列挙します。

そのため、オブジェクト自身が持っていないプロパティも列挙されてしまい、意図しない結果になる場合があります。


安全にオブジェクトのプロパティを列挙するには、Object.keysメソッド、Object.valuesメソッド、Object.entriesメソッドなどが利用できます。

オブジェクトのキーと値を列挙するコードはfor...in文を使わずに書けます。 Object.keysメソッドは引数のオブジェクト自身が持つ列挙可能なプロパティ名の配列を返します。

そのためfor...in文とは違い、親オブジェクトのプロパティは列挙されません。

const obj={
    "a":1,
    "b":2,
    "c":3
};
Object.keys(obj).forEach(key=>{
    const value=obj[key];
    console.log(`key:${key},value:${value}`);
});

key:a,value:1
key:b,value:2
key:c,value:3

また、for…in文は配列に対しても利用できますが、こちらも期待した結果にはなりません。

下記のコードでは、配列の要素が列挙されそうですが、実際には配列のプロパティ名が列挙されます。

for…in文が列挙する配列オブジェクトのプロパティ名は、要素のインデックスを文字列化した0、1となるため、その文字列がnumへと順番に代入されます。

そのため数値と文字列の加算が行われ、意図した結果にはなりません。

const numbers=[5,10];
let total=0;
for(const num in numbers){
    total +=num;
}
console.log(total);

001

for…in文は正しく扱うのが難しいため、代わりとなる手段が豊富にあります。

for…in文の利用は避けObject.keysメソッドなどを使って配列として反復処理するなど別の方法を考えた方がよいでしょう。