JSX で Array#forEach が5倍以上速くなった話

JSX の進化速度が半端ない - ぐるぐる~ で紹介していただいているとおり、最新の JSX では function expression の型宣言を省略できるようになっています。これを利用して、たとえば配列の合計を求める場合、

var sum = 0;
[ 1, 2, 3, 4, 5, 6, 7, 8 ].forEach(function (n) { sum += n; });

のように、JavaScript と 100% 同様に書くことができるようになりました。省略形を利用して [ ... ].forEach((n) -> { sum + n; }); でもいいです。

ところでこのコード、見た目は同じなんですが、実は JSX だと JavaScript よりも5倍以上速く動くんです。まだ最適化があまいところがあるのに。

なぜか。JavaScript の Array#forEach は配列の要素ごとに関数の呼び出しが発生するので遅いのです。じゃあ、

var a = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
var sum = 0;
for (var i = 0; i < a.length; ++i) {
  sum += a[i];
}

と書けばいいのでしょうか。いえいえ、それではまだ不足です。ループの度に Array#length へのアクセスしているのが、足をひっぱります。JavaScript におけるプロパティアクセスは遅いのです。

var a = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
var sum = 0;
for (var i = 0, aLen = a.length; i < aLen; ++i) {
  sum += a[i];
}

これなら、まあ合格です。ただ Safari だと for ループの中に var 宣言を入れると遅くなるので、さらに言うなら

var a = [ 1, 2, 3, 4, 5, 6, 7, 8 ];
var sum = 0;
var i, aLen;
for (i = 0, aLen = a.length; i < aLen; ++i) {
  sum += a[i];
}

と書くべきなんですが…こんなバッドノウハウ、いちいち覚えたくないし使いたくないですね。

JSX なら、このような最適化を自動的にやってくれるわけです。楽チン楽チン。

以上、宣伝でした。ベンチマークsum-of-array · jsPerf にあるのでお試しあれ。