2017年度版 細かすぎて伝わらないJavaScriptの速度の話のコードを、コピペして動かしやすいように全文書いてみた話

## そういう話です

察してください。

[2017年度版 細かすぎて伝わらないJavaScriptの速度の話 - Qiita](http://qiita.com/gctoyo/items/31b982092b61fe9072dc)

全部動かしました。

## ベンチマーク関数を手に入れて嬉しかったので、ノリで

ベンチマーク関数の作り方を教えてもらったので、嬉しくてつい、ベンチマークしてみました。

[JavaScript で全置換(正規表現も使った)の速度比較 - Qiita](http://qiita.com/standard-software/items/d86a91dac6f7f317087c)

[JavaScript ベンチマーク関数などで実行する関数と引数を渡して動作させたい - スタック・オーバーフロー](https://ja.stackoverflow.com/questions/35092/javascript-%e3%83%99%e3%83%b3%e3%83%81%e3%83%9e%e3%83%bc%e3%82%af%e9%96%a2%e6%95%b0%e3%81%aa%e3%81%a9%e3%81%a7%e5%ae%9f%e8%a1%8c%e3%81%99%e3%82%8b%e9%96%a2%e6%95%b0%e3%81%a8%e5%bc%95%e6%95%b0%e3%82%92%e6%b8%a1%e3%81%97%e3%81%a6%e5%8b%95%e4%bd%9c%e3%81%95%e3%81%9b%e3%81%9f%e3%81%84)

## 結果

* chrome windows (mac上のvwwareですけれども何か文句が....)

> 1394 msec ダブルクウォート
> 1201 msec シングルクウォート
> 218 msec if
> 185 msec switch
> 215 msec x++
> 229 msec x = (x + 1);
> 213 msec x = (x + 1)|0;
> 1050 msec + 連結
> 2564 msec concat 連結
> 1708 msec テンプレートリテラル
> 2351 msec += 連結
> 243 msec typeof x === "undefined"
> 206 msec x === undefined
> 265 msec x === void 0
> 193 msec if (!x) {}
> 217 msec if (x) {}
> 198 msec if (x === true) {}
> 213 msec if (!x) {}
> 241 msec if (x === false) {}
> 281 msec scope01++;
> 230 msec this.scope02++;
> 229 msec scope03++;
> 183 msec const test = 0;
> 2486 msec const test = new Test();
> 186 msec tryなし
> 146 msec Try/Catch
> 162 msec Try/Catch/Finally
> load

* node.js windows (mac上のvwwareですけれども文句ないよな。スタバでドヤ顔するためだけに使ってるんだから。windowsの方が使いやすいし。winmergeとかあるし)

> 983 msec ダブルクウォート
> 967 msec シングルクウォート
> 173 msec if
> 156 msec switch
> 203 msec x++
> 203 msec x = (x + 1);
> 172 msec x = (x + 1)|0;
> 876 msec + 連結
> 1888 msec concat 連結
> 1513 msec テンプレートリテラル
> 1841 msec += 連結
> 218 msec typeof x === "undefined"
> 204 msec x === undefined
> 203 msec x === void 0
> 171 msec if (!x) {}
> 172 msec if (x) {}
> 187 msec if (x === true) {}
> 187 msec if (!x) {}
> 172 msec if (x === false) {}
> 250 msec scope01++;
> 218 msec this.scope02++;
> 218 msec scope03++;
> 172 msec const test = 0;
> 546 msec const test = new Test();
> 171 msec tryなし
> 156 msec Try/Catch
> 172 msec Try/Catch/Finally
> node.js

## コード全文

```HTML:index.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="script.js"></script>

<script>

var alert = function (message) {
	console.log(message);
};

window.addEventListener("load",function(eve){
    main('load');
},false);

</script>

  </head>
<body>

<form name="form01">
<table class="table02">
  <tr>
    <td>
      <input type="button" value="Test01" onclick="main('test01')" 
        style="width:150px;">

    </td>
  </tr>

  <tr>
    <td>
      <input type="button" value="Test02" onclick="main('test02')" 
        style="width:150px;">

    </td>
  </tr>

</table>
</form>


</body>
</html>
```

```JavaScript:script.js
var alert = alert || function (message) {
	console.log(message);
};

var main = function (testName) {

  var benchMark = function (loopCount, func) {
    var startTime = new Date();

    var args = [].slice.call(arguments,2);

    for (var i = 0, max = loopCount - 1;
      i <= max - 1; i += 1) {
      func.apply(null, args);
    }

    var endTime = new Date();
    return endTime - startTime;
  }

  start = () => {
    const retryCount = 1000000;
    for (let i = 0; i < retryCount; i = i + 1) {
      const text = "abcde" + "fghij" + "klmno" + "pqrst" + "uvwxy" + "z" + i;
    }
  }
  console.log(benchMark(10, start) + ' msec ダブルクウォート');

  start = () => {
    const retryCount = 1000000;
    for (let i = 0; i < retryCount; i = i + 1) {
      const text = 'abcde' + 'fghij' + 'klmno' + 'pqrst' + 'uvwxy' + 'z' + i;
    }
  }
  console.log(benchMark(10, start) + ' msec シングルクウォート');

  start = () => {
    for (let i = 0; i < 10000000; i = i + 1) {
      const x = 1;
      // if
      if ( x === 1) {}
      else if ( x === 2) {}
      else if ( x === 3) {}
      else {}
    }
  }
  console.log(benchMark(10, start) + ' msec if');

  start = () => {
    for (let i = 0; i < 10000000; i = i + 1) {
      const x = 1;
      // switch
      switch (x) {
        case 1:
          break;
        case 2:
          break;
        case 3:
          break;
        default:
          break;
      }
    }
  }
  console.log(benchMark(10, start) + ' msec switch');

  start = () => {
    let x = 1;
    for (let i = 0; i < 10000000; i = i + 1) {
      x++;
    }
  }
  console.log(benchMark(10, start) + ' msec x++');

  start = () => {
    let x = 1;
    for (let i = 0; i < 10000000; i = i + 1) {
      x = (x + 1);
    }
  }
  console.log(benchMark(10, start) + ' msec x = (x + 1);');

  start = () => {
    let x = 1;
    for (let i = 0; i < 10000000; i = i + 1) {
      x = (x + 1)|0;
    }
  }
  console.log(benchMark(10, start) + ' msec x = (x + 1)|0;');

  start = () => {
    const a = "abcde";
    const f = "fghij";
    const k = "klmno";
    const p = "pqrst";
    const u = "uvwxyz";
    for (let i = 0; i < 1000000; i = i + 1) {
      let text = a + f + k + p + u + i;
    }
  }
  console.log(benchMark(10, start) + ' msec + 連結');

  start = () => {
    const a = "abcde";
    const f = "fghij";
    const k = "klmno";
    const p = "pqrst";
    const u = "uvwxyz";
    for (let i = 0; i < 1000000; i = i + 1) {
      let text = a.concat(f).concat(k).concat(p).concat(u).concat(i);
    }
  }
  console.log(benchMark(10, start) + ' msec concat 連結');

  start = () => {
    const a = "abcde";
    const f = "fghij";
    const k = "klmno";
    const p = "pqrst";
    const u = "uvwxyz";
    for (let i = 0; i < 1000000; i = i + 1) {
      let text = `${a}${f}${k}${p}${u}${i}`;
    }
  }
  console.log(benchMark(10, start) + ' msec テンプレートリテラル');

  start = () => {
    const a = "abcde";
    const f = "fghij";
    const k = "klmno";
    const p = "pqrst";
    const u = "uvwxyz";
    for (let i = 0; i < 1000000; i = i + 1) {
      let text = a;
      text += f;
      text += k;
      text += p;
      text += u;
      text += i;
    }
  }
  console.log(benchMark(10, start) + ' msec += 連結');

  start = () => {
    let x;
    for (let i = 0; i < 10000000; i = i + 1) {
      if (typeof x === 'undefined') {}
    }
  }
  console.log(benchMark(10, start) + ' msec typeof x === "undefined"');

  start = () => {
    let x;
    for (let i = 0; i < 10000000; i = i + 1) {
      if (x === undefined) {}
    }
  }
  console.log(benchMark(10, start) + ' msec x === undefined');

  start = () => {
    let x;
    for (let i = 0; i < 10000000; i = i + 1) {
      if (x === void 0) {}
      /* if (!x) {} */
    }
  }
  console.log(benchMark(10, start) + ' msec x === void 0');

  start = () => {
    let x;
    for (let i = 0; i < 10000000; i = i + 1) {
      if (!x) {}
    }
  }
  console.log(benchMark(10, start) + ' msec if (!x) {}');

  start = () => {
    const x = true;
    for(let i = 0; i < 10000000; i = i + 1) {
      if (x) {}
    }
  }
  console.log(benchMark(10, start) + ' msec if (x) {}');

  start = () => {
    const x = true;
    for(let i = 0; i < 10000000; i = i + 1) {
      if (x === true) {}
    }
  }
  console.log(benchMark(10, start) + ' msec if (x === true) {}');

  start = () => {
    const x = true;
    for(let i = 0; i < 10000000; i = i + 1) {
      if (!x) {}
      /* if (x === false) {} */
    }
  }
  console.log(benchMark(10, start) + ' msec if (!x) {}');

  start = () => {
    const x = true;
    for(let i = 0; i < 10000000; i = i + 1) {
      if (x === false) {}
    }
  }
  console.log(benchMark(10, start) + ' msec if (x === false) {}');

  scope01 = 1;
  class Test1 {
    constructor() {
      this.scope02 = 1;
    }
    start() {
      let scope03 = 1;
      for(let i = 0; i < 10000000; i = i + 1) {
         scope01++;
      }
    }
  }
  start = () => {
    const test = new Test1();
    test.start();
  }
  console.log(benchMark(10, start) + ' msec scope01++;');

  scope01 = 1;
  class Test2 {
    constructor() {
      this.scope02 = 1;
    }
    start() {
      let scope03 = 1;
      for(let i = 0; i < 10000000; i = i + 1) {
         this.scope02++;
      }
    }
  }
  start = () => {
    const test = new Test2();
    test.start();
  }
  console.log(benchMark(10, start) + ' msec this.scope02++;');

  scope01 = 1;
  class Test3 {
    constructor() {
      this.scope02 = 1;
    }
    start() {
      let scope03 = 1;
      for(let i = 0; i < 10000000; i = i + 1) {
         scope03++;
      }
    }
  }
  start = () => {
    const test = new Test3();
    test.start();
  }
  console.log(benchMark(10, start) + ' msec scope03++;');

  class Test {
    constructor() {}
  }
  start = () => {
    for(let i = 0; i < 10000000; i = i + 1) {
      const test = 0;
    }
  }
  console.log(benchMark(10, start) + ' msec const test = 0;');

  start = () => {
    for(let i = 0; i < 10000000; i = i + 1) {
      const test = new Test();
    }
  }
  console.log(benchMark(10, start) + ' msec const test = new Test();');

  start = () => {
    for(let i = 0; i < 10000000; i = i + 1) {
      const x = 0;
    }
  }
  console.log(benchMark(10, start) + ' msec tryなし');

  start = () => {
    for(let i = 0; i < 10000000; i = i + 1) {
      try {
        const x = 0;
      }
      catch (exception) {}
    }
  }
  console.log(benchMark(10, start) + ' msec Try/Catch');

  start = () => {
    for(let i = 0; i < 10000000; i = i + 1) {
      try {
        const x = 0;
      }
      catch (exception) {}
      finally {}
    }
  }
  console.log(benchMark(10, start) + ' msec Try/Catch/Finally');

  alert(testName);
}

if (typeof module !== 'undefined') {
  module.exports = main;
}

```

```JavaScript:call_script_node.js

var main = require('./script.js');
main('node.js');

```

```bat:run_node_script.bat
node call_script_node.js
pause
```


## 感想

ちょっとコピペが大変でした。ベンチマーク関数の呼び出しのオーバーヘッド的な不正確さがあるかもしれませんが、そこはみなかったことにしてください。

ご自身の環境でいろんなブラウザで試したりしてもいいんじゃないでしょうか。

全体的に差がほとんどなくて、誤差に近いきがしなくも、ないところもありますが、文字列の結合などはすごく差がありますね。

元ネタを提供していただいて、インスピレーションくださった、@gctoyoさん、大変ありがとうございます。