理由がない限り、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() を使う必然性のあるケースは以下の場合に限定されるようです、

  • Array.join(",") のように、要素間にセパレータを埋め込む場合
  • IE で沢山(30〜?)の要素数がある場合

これ以外なら、"文字列" + "文字列" + ... が速いようですね。

ブラウザによってはループ中の普遍的な部分を最適化する(ループの外に出してしまう)ため、今回のケースでは最適化されないように、変数 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;
}