All Articles

JavaScriptのSwitch文について本気出して調べた話

突然ですが、問題。以下のテストはパスするでしょうか。

lib.js

export default function selectCase(tmp) {
    switch ( tmp ) {
        case 1:
            return "This is one";
        default:
            throw new Error("Unexpected value");
    }
}

lib.test.js

import assert from "power-assert";
import selectCase from "./lib.js";

describe("selectCase testing"undefined () => {
    it ("expect This is one"undefined () => {
        assert(selectCase("1") === "This is one");
    });
    it ("Throws error"undefined () => {
        assert.throws(() => {
            selectCase("Foo");
        }undefined Error);
    });
});
$ mocha —compilers js:espower-babel/guess lib.test.js

答えは…パスしません(´;ω;`)

いつからswitch-case文が等値演算子だと錯覚していた?

いつからか全く記憶が無いのですが、恥ずかしながらJavaScriptのswitch-caseのCompletionって等値演算子だと思ってたようです…。ただ同値演算子であるという根拠が欲しかったので色々調べた午前2時。

ES6のSpecは?

ES6のSpecを調べてみた。

https://people.mozilla.org/~jorendorff/es6-draft.html#sec-runtime-semantics-caseblockevaluation

13.11.9 Runtime Semantics: CaseBlockEvaluationの項に、

Let found be the result of performing Strict Equality Comparison input === clauseSelector.[[value]].

とあります。同値演算子だ。

V8の実装は?

いやいや、言うてもブラウザの実装はわからんでしょ?ってことでV8のソースを漁る。

https://chromium.googlesource.com/v8/v8.git/+/master/src/x87/full-codegen-x87.cc

988行目のコメント。

// Perform the comparison as if via ’===‘.

あっ…

完全論破された

間違いなく同値演算子でした。ちなみにサイ本(第5版)にはこんなサンプルコードが。

switch(n) {
  case 1:      // n == 1 の場合、ここから開始する。
    // コードブロック #1を実行する。
    break;
  case 2:
...

…。

ちなみに、次のページくらいに、

値は、等値演算子(==)ではなく、同値演算子(===)を使って比較されます。つまり、型変換は行われません。

と書かれています。うん、サンプルコードのコメントおかしいよね。

まとめ

多分PHPのswitch文と混同しちゃってたんだろうなぁ。恥ずかしい。 普段から型を意識してキャストするなりして書きましょうって話ですね。