JavaScriptコーディング ベストプラクティス 高速かつ堅牢なコードを効率よく書くためにの主に第4章で紹介されている「高速化のためのベンチマークコレクション」をもう少し突っ込んで調べてみたくなったので調べてみました。

今回は第1回目(2回目があるかは知らないよ)として、書籍では4.2.19「スコープ内外への変数へのアクセス速度」です。
追加した検証内容とあわせるために、無名関数を即時実行する方法に若干の修正をしています。ローカル変数が最も速いのは調べるまでもないのでブラウザはChrome10の結果のみ記載します。決して手を抜いた訳じゃあないよ。

// (1) window.aへのアクセス
for(var i = 0; i < 1000000; i++){
  window.a = 'abc';
}

// (1’) 関数内でwindow.aへのアクセス(書籍にも記載)
(function(){
  for(var i = 0; i < 1000000; i++){
    window.a = 'abc';
  }
})();

// (2) window['a']へのアクセス
for(var i = 0; i < 1000000; i++){
  window['a'] = 'abc';
}

// (2’) 関数内でwindow['a']へのアクセス
(function(){
  for(var i = 0; i < 1000000; i++){
    window['a'] = 'abc';
  }
})();

// (3) 暗黙のグローバル変数へのアクセス
for(var i = 0; i < 1000000; i++){
  a = 'abc';
}

// (3’) 関数内で暗黙のグローバル変数へのアクセス
(function(){
  for(var i = 0; i < 1000000; i++){
    a = 'abc';
  }
})();

// (4) ローカルスコープに参照をコピーしたwindow.aへのアクセス
(function(w){
  for(var i = 0; i < 1000000; i++){
    w.a = 'abc';
  }
})(window);

// (5) ローカルスコープに参照をコピーしたwindow['a']へのアクセス
(function(w){
  for(var i = 0; i < 1000000; i++){
    w['a'] = 'abc';
  }
})(window);

// (6) 関数内でローカル変数aへのアクセス(書籍にも記載)
(function(){
  var a = '';
  for(var i = 0; i < 1000000; i++){
    a = 'abc';
  }
})();

結果は以下の通り。

(1) 1685ms
(1’) 705ms
(2) 1690ms
(2’) 718ms
(3) 1290ms
(3’) 307ms
(4) 190ms
(5) 191ms
(6) 7ms

ローカル変数は別格なのでここでは放っておきますが、グローバル変数については様々なアクセス方法がある中で、大きく分けて5つのポイントが見えました。

  1. ドット参照も添字参照も違いはない
  2. 暗黙のグローバル変数はちょっと速い(ただし第3者からみてvarつけ忘れか狙ったのか判断しづらいので使ってほしくない)
  3. 明示的にwindowオブジェクトから参照するのが最も遅い
  4. ただしローカルスコープから参照させると一気に改善する(よくいわれてるよね)
  5. 同じグローバル変数への参照でもfunction内部で実行すると速度が2倍速くなる

特に最後のポイントは意外でした。他はともかく(やる前から大体見当のつくものだし)これだけはどう解釈していいのか分かりません。1つ言えるのは、日頃から無名関数の即時実行してローカルスコープを作るコードを書く癖があればそれだけで多少速度改善に貢献していたということですね。

また気になった高速化のポイントがあれば調べてみたいと思います。