理由がない限り、Array.join("") による文字列連結は使わないほうがいいみたい
JavaScript の勉強を開始したときに「文字列の連結には Array.join() を使え」といった記事を見た覚えがあります(ソース失念したけど、 Operaの技術文書だった気がする ⇒ IE の技術文書だったかも)。
一年ほど信じてて、念のためベンチとってみたら「うそやーん」でした。ってお話。
ベンチの条件は、
- 3種類の文字列連結方法を試す
- 1. + Operator
- 2. String.concat()
- 3. Array.join("")
- 文字列の要素数を 11個 と 55個で試す
<!doctype html><html><head><title></title> </head><body> <script> window.onload = function() { var now = +new Date, lp = 100; while (lp--) { job(); } document.getElementById("view").innerHTML = ((+new Date) - now); } function job() { var i = 0, r = ""; for(; i < 1000; ++i) { // ▼▼▼▼▼ ここを変える(これは55個版) ▼▼▼▼ r = "base" + "1"+"2"+"3"+"4"+"5"+"6"+"7"+"8"+"9" + i + "base" + "1"+"2"+"3"+"4"+"5"+"6"+"7"+"8"+"9" + i + "base" + "1"+"2"+"3"+"4"+"5"+"6"+"7"+"8"+"9" + i + "base" + "1"+"2"+"3"+"4"+"5"+"6"+"7"+"8"+"9" + i + "base" + "1"+"2"+"3"+"4"+"5"+"6"+"7"+"8"+"9" + i; // ▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲▲ } } </script><div id="view"></div></body></html>
r = str.concat("base", "1","2","3","4","5","6","7","8","9", i, "base", "1","2","3","4","5","6","7","8","9", i, "base", "1","2","3","4","5","6","7","8","9", i, "base", "1","2","3","4","5","6","7","8","9", i, "base", "1","2","3","4","5","6","7","8","9", i);
r = ["base", "1","2","3","4","5","6","7","8","9", i, "base", "1","2","3","4","5","6","7","8","9", i, "base", "1","2","3","4","5","6","7","8","9", i, "base", "1","2","3","4","5","6","7","8","9", i, "base", "1","2","3","4","5","6","7","8","9", i].join("");
結果
要素数 11個
Browser | + operator | String.concat | Array.join | 速度差 | |
Opera9.52 | 422 | 921 | 1734 | 4倍 | |
Opera10RC | 344 | 828 | 1593 | 4.6倍 | |
Firefox2 | 1750 | 1797 | 5281 | 3倍 | |
Firefox3 | 332 | 339 | 1296 | 4倍 | |
Firefox3.5 | 249 | 251 | 532 | 2倍 | |
IE6 | 1062 | 1172 | 1297 | 1.2倍 | |
IE7 | 1078 | 1188 | 1296 | 1.2倍 | |
IE8 | 609 | 625 | 922 | 1.5倍 | |
Chrome4 | 124 | 368 | 327 | 2.5倍 | |
Safari4 | 98 | 137 | 176 | 1.8倍 |
要素数 55個
Browser | + operator | String.concat | Array.join | 速度差 | |
Opera9.52 | 2140 | 3718 | 9204 | 4.3倍 | |
Opera10RC | 1516 | 3297 | 7610 | 5倍 | |
Firefox2 | 4484 | 4406 | タイムアウト | - | |
Firefox3 | 2085 | 1756 | 3411 | 1.6倍 | |
Firefox3.5 | 1117 | 1224 | 1941 | 1.7倍 | |
IE6 | 5594 | 5500 | 4297 | 0.7倍 | |
IE7 | 5641 | 5578 | 4328 | 0.7倍 | |
IE8 | 3187 | 3062 | 2453 | 0.7倍 | |
Chrome4 | 537 | 1409 | 1185 | 2.2倍 | |
Safari4 | 416 | 529 | 442 | とんとん? |
この結果から、Array.join() を使う必然性のあるケースは以下の場合に限定されるようです、
これ以外なら、"文字列" + "文字列" + ... が速いようですね。
ブラウザによってはループ中の普遍的な部分を最適化する(ループの外に出してしまう)ため、今回のケースでは最適化されないように、変数 i の値を文字列に加えています。
気になる人は条件変えて(文字列長くするとか)追試するといいよ。
追記
50個もの文字列を一気に扱う場面は通常そんなになくて、「配列に格納されている文字列を、ループで一個ずつ取り出し、文字列に追加するやり方をするんだったら、Array.join("") 使うべき」というケースへの配慮が欠けてました。
つまり、これ(↓)に近いやり方で、文字列をちょっとずつ結合するのは NG
function join(ary) { var rv = ""; for (var i = 0, iz = ary.length; i < iz; ++i) { rv += ary[i]; } return rv; }
それよりも、配列に溜めておいて、一気に Array.join("") を使うべきだよ。という話
function join(ary) { return ary.join(""); }
当たり前すぎて書かないほうが良かったかもしれませんが。追記してみました。
ここからが本題
関数内にちょこっとした文字列があって、それをわざわざ Array.join("") しているようなケースなら、+ で直に連結したほうが地球に優しいコードになりそうです。
つまり、今まではわざわざこう(↓)していたものを…
function hoge() { var a = "a", b = "b", c = "c", d = "d", e = "e"; return [a, b, c, d, e].join(""); }
明日からは、こうすると良いかもね
function hoge() { var a = "a", b = "b", c = "c", d = "d", e = "e"; return a + b + c + d + e; }