条件分岐

この章ではif文やswitch文を使った条件分岐について学んでいきます。 条件分岐を使うことで、特定の条件を満たすかどうかで行う処理を変更できます。

if文

if文を使うことで、プログラム内に条件分岐を書けます。

if文は次のような構文が基本形となります。 条件式の評価結果がtrueであるならば、実行する文が実行されます。

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

次のコードでは条件式trueであるため、ifの中身が実行されます。

if (true) {
    console.log("この行は実行されます");
}

実行する文が1つのみの場合は、{} のブロックを省略できます。 しかし、どこまでがif文かがわかりにくくなるため、常にブロックで囲むことを推奨します。

if (true)
    console.log("この行は実行されます");

if文は条件式に比較演算子などを使い、その比較結果によって処理を分岐するためによく使われます。 次のコードでは、x10よりも大きな値である場合に、if文の中身が実行されます。

const x = 42;
if (x > 10) {
    console.log("xは10より大きな値です");
}

if文の条件式にはtrueまたはfalseといった真偽値以外の値も指定できます。 真偽値以外の値の場合、その値を暗黙的に真偽値へ変換してから、条件式として判定します。

真偽値へ変換するとtrueとなる値の種類は多いため、逆に変換した結果がfalseとなる値を覚えるのが簡単です。 次の値は真偽値へと変換するとfalseとなるため、これらはfalsyな値と呼ばれます(「暗黙的な型変換」の章を参照)。

  • false
  • undefined
  • null
  • 0
  • 0n
  • NaN
  • ""(空文字列)

falsyではない値は、trueへと変換されます。 そのため、"文字列"や0以外の数値などを条件式に指定した場合は、trueへと変換してから条件式として判定します。

次のコードは、条件式がtrueへと変換されるため、if文の中身が実行されます。

if (true) {
    console.log("この行は実行されます");
}
if ("文字列") {
    console.log("この行は実行されます");
}
if (42) {
    console.log("この行は実行されます");
}
if (["配列"]) {
    console.log("この行は実行されます");
}
if ({ name: "オブジェクト" }) {
    console.log("この行は実行されます");
}

falsyな値を条件式に指定した場合は、falseへと変換されます。 次のコードは、条件式がfalseへと変換されるため、if文の中身は実行されません。

if (false) {
    // この行は実行されません
}
if ("") {
    // この行は実行されません
}
if (0) {
    // この行は実行されません
}
if (undefined) {
    // この行は実行されません
}
if (null) {
    // この行は実行されません
}

else if文

複数の条件分岐を書く場合は、if文に続けてelse if文を使うことで書けます。 たとえば、次の3つの条件分岐するプログラムを考えます。

  • version"ES5" ならば "ECMAScript 5" と出力
  • version"ES6" ならば "ECMAScript 2015" と出力
  • version"ES7" ならば "ECMAScript 2016" と出力

次のコードでは、if文とelse if文を使うことで3つの条件を書いています。 変数versionの値が"ES6"であるため、コンソールには"ECMAScript 2015"が出力されます。

const version = "ES6";
if (version === "ES5") {
    console.log("ECMAScript 5");
} else if (version === "ES6") {
    console.log("ECMAScript 2015");
} else if (version === "ES7") {
    console.log("ECMAScript 2016");
}

else文

if文とelse if文では、条件に一致した場合の処理をブロック内に書いていました。 一方で条件に一致しなかった場合の処理は、else文を使うことで書けます。

次のコードでは、変数numの数値が10より大きいかを判定しています。 numの値は10以下であるため、else文で書いた処理が実行されます。

const num = 1;
if (num > 10) {
    console.log(`numは10より大きいです: ${num}`);
} else {
    console.log(`numは10以下です: ${num}`);
}

ネストしたif文

if文、else if文、else文はネストして書けます。 次のように複数の条件を満たすかどうかをif文のネストとして表現できます。

if (条件式A) {
    if (条件式B) {
        // 条件式Aと条件式Bがtrueならば実行される文
    }
}

ネストしたif文の例として、今年がうるう年かを判定してみましょう。

うるう年の条件は次のとおりです。

  • 西暦で示した年が4で割り切れる年はうるう年です
  • ただし、西暦で示した年が100で割り切れる年はうるう年ではありません
  • ただし、西暦で示した年が400で割り切れる年はうるう年です

西暦での現在の年は new Date().getFullYear(); で取得できます。 このうるう年の条件をif文で表現すると次のように書けます。

const year = new Date().getFullYear();
if (year % 4 === 0) { // 4で割り切れる
    if (year % 100 === 0) { // 100で割り切れる
        if (year % 400 === 0) { // 400で割り切れる
            console.log(`${year}年はうるう年です`);
        } else {
            console.log(`${year}年はうるう年ではありません`);
        }
    } else {
        console.log(`${year}年はうるう年です`);
    }
} else {
    console.log(`${year}年はうるう年ではありません`);
}

条件を上から順に書き下したため、ネストが深い文となってしまっています。 一般的にはネストは浅いほうが、読みやすいコードとなります。

条件を少し読み解くと、400で割り切れる年は無条件にうるう年であることがわかります。 そのため、条件を並び替えることで、ネストするif文なしに書くことができます。

const year = new Date().getFullYear();
if (year % 400 === 0) { // 400で割り切れる
    console.log(`${year}年はうるう年です`);
} else if (year % 100 === 0) { // 100で割り切れる
    console.log(`${year}年はうるう年ではありません`);
} else if (year % 4 === 0) { // 4で割り切れる
    console.log(`${year}年はうるう年です`);
} else { // それ以外
    console.log(`${year}年はうるう年ではありません`);
}

switch文

switch文は、次のような構文での評価結果が指定した値である場合に行う処理を並べて書きます。

switch (式) {
    case ラベル1:
        // `式`の評価結果が`ラベル1`と一致する場合に実行する文
        break;
    case ラベル2:
        // `式`の評価結果が`ラベル2`と一致する場合に実行する文
        break;
    default:
        // どのcaseにも該当しない場合の処理
        break;
}
// break; 後はここから実行される

switch文はif文と同様にの評価結果に基づく条件分岐を扱います。 またbreak文は、switch文から抜けてswitch文の次の文から実行するためのものです。 次のコードでは、versionの評価結果は"ES6"となるため、case "ES6":に続く文が実行されます。

const version = "ES6";
switch (version) {
    case "ES5":
        console.log("ECMAScript 5");
        break;
    case "ES6":
        console.log("ECMAScript 2015");
        break;
    case "ES7":
        console.log("ECMAScript 2016");
        break;
    default:
        console.log("しらないバージョンです");
        break;
}
// "ECMAScript 2015" と出力される

これはif文で次のように書いた場合と同じ結果になります。

const version = "ES6";
if (version === "ES5") {
    console.log("ECMAScript 5");
} else if (version === "ES6") {
    console.log("ECMAScript 2015");
} else if (version === "ES7") {
    console.log("ECMAScript 2016");
} else {
    console.log("しらないバージョンです");
}

switch文はやや複雑な仕組みであるため、どのように処理されているかを見ていきます。 まず switch (式)を評価します。

switch (式) {
    // case
}

次にの評価結果が厳密等価演算子(===)で一致するラベルを探索します。 一致するラベルが存在する場合は、そのcase節を実行します。 一致するラベルが存在しない場合は、default節が実行されます。

switch (式) {
    // if (式 === "ラベル1")
    case "ラベル1":
        break;
    // else if (式 === "ラベル2")
    case "ラベル2":
        break;
    // else
    default:
        break;
}

break文

switch文のcase節では基本的にbreak;を使ってswitch文を抜けるようにします。 このbreak;は省略が可能ですが、省略した場合、後ろに続くcase節が条件に関係なく実行されます。

const version = "ES6";
switch (version) {
    case "ES5":
        console.log("ECMAScript 5");
    case "ES6": // 一致するケース
        console.log("ECMAScript 2015");
    case "ES7": // breakされないため条件無視して実行
        console.log("ECMAScript 2016");
    default:    // breakされないため条件無視して実行
        console.log("しらないバージョンです");
}
/*
 "ECMAScript 2015"
 "ECMAScript 2016"
 "しらないバージョンです"
 と出力される
 */

このようにbreak;を忘れてしまうと意図しないcase節が実行されてしまいます。 そのため、case節とbreak文が多用されているswitch文が出てきた場合、 別の方法で書けないかを考えるべきサインとなります。

switch文はif文の代用として使うのではなく、次のように関数と組み合わせて条件に対する値を返すパターンとして使うことが多いです。 関数については「関数と宣言」の章を参照してください。

function getECMAScriptName(version) {
    switch (version) {
        case "ES5":
            return "ECMAScript 5";
        case "ES6":
            return "ECMAScript 2015";
        case "ES7":
            return "ECMAScript 2016";
        default:
            return "しらないバージョンです";
    }
}
// 関数を実行して`return`された値を得る
getECMAScriptName("ES6"); // => "ECMAScript 2015"

まとめ

この章では条件分岐について学びました。

  • if文、else if文、else文で条件分岐した処理を扱える
  • 条件式に指定した値は真偽値へと変換してから判定される
  • 真偽値に変換するとfalseとなる値をfalsyと呼ぶ
  • switch文とcase節、default節を組み合わせて条件分岐した処理を扱える
  • case節でbreak文を省略した場合は、後ろに続くcase節が実行される

条件分岐にはif文やswitch文を利用します。 複雑な条件を定義する場合には、if文のネストが深くなりやすいです。 そのような場合には、条件式自体を見直してよりシンプルな条件にできないかを考えてみることも重要です。