ブロックスコープを作る構文をちゃんと性能比較してみました。
前回の記事で書いたcreateScope関数もセットにしました。
function createScope(prev) {
var newScope, Scope=createScope.Scope;
if (prev instanceof Object) {
Scope.prototype = prev;
newScope = new Scope;
newScope.__outer__ = prev;
return newScope;
} else {
Scope.prototype = null;
return new Scope;
}
}
createScope.Scope = function(){ this.my = this };
ひとまずFirefoxでの測定結果をのせます。
ブロック自体の生成速度
| ブロックなし | 0 |
| (function(){})() | 0 |
| new function(){} | 26 |
| with({}){} | 6 |
| with(createScope()){} | 8 |
中身がほとんど空っぽのブロックを作りまくるようにして測定した結果です。無名関数やwithが速く、意外と無名コンストラクタが遅いですね。
ブロック内の変数参照速度
| 名前 | 0階層 | 1階層 | 2階層 | 3階層 |
|---|---|---|---|---|
| (function(){})() | 1 | 3 | 3 | 3 |
| new function(){} | 1 | 3 | 4 | 3 |
| with({}){} | 79 | 131 | 166 | 201 |
| with(createScope()){} | 80 | 79 | 80 | 85 |
ブロックの生成は必要最低限にして、ブロック内に処理を記述した比較結果です。階層というのはブロックを入れ子にしていったときの比較です。
予想通り、無名関数と無名コンストラクタに処理速度の違いはなく、そしてwithが圧倒的に遅いです。ただ、createScope関数でスコープチェーンの代わりにプロトタイプチェーンを使うという戦略はうまくいっているみたいです。with自体が遅すぎて意味がないようですが。
withが遅い理由はamachangさんが書いていた記事がわかりやすかったです。
for 文と無名関数のイディオム - IT戦記
要は最適化が難しいから、ということです。withブロックの中では全ての変数参照速度が遅くなります。withブロックの中であっても、変数参照が非常に少ないようなプログラムなら、あまりwithで囲んでも囲まなくても差は出ないかもしれません。
まとめ
withはやっぱり遅かった。