JavaScriptで ""+x を文字列変換に使うのは気持ち悪い

JavaScriptの本やブログなどで非常に良く見かけるのだが、数値などの文字列でないものを文字列に変換する方法として

var s = "" + x;

のように空文字との連結によって行っているが、私としてはちょっと気持ち悪さを感じる。もちろん、間違いではない。確かにxは文字列に変換される。+の左側が空文字でなく、何かの文字が書かれている場合には、普通にやることだ。空文字との連結に違和感がある。じゃ、どう書くかというと、

var s = String(x);

と書く。なんか、タイプ数が増えるし面倒じゃん?という声が聞こえてきそうだが、Stringという引数を文字列に変換するという目的そのものの関数が定義されているのに、わざわざ + 演算子を使うことが気持ち悪いのである。しかも、+ 演算子という多層演算子を使うのでコードが読みにくい。さらに、上のような書き方があまりにも普及してしまっていて、Stringにこのような関数としての機能があることが知られていないのではないか、という懸念もある。

しかし、いくら気持ち悪いなどと言っても、実用的なメリットがなければ単に好みの問題になってしまう。たとえ、一方が正しくても、それがマイナーな場合、可読性とか美しさとかを主張してもなかなか納得してもらえない。そこで、パフォーマンスに違いがあるかどうかを調べてみた。

以下のような簡単なベンチマークで計測してみた。

function perf(x) {
  var s;
  while (x-- > 0) {
    s = "" + x;
  }
}

function test() {
  var n = 5000000;
  var tm1 = (new Date).getTime();
  perf(n);
  var tm2 = (new Date).getTime();
  alert("tm=" + (tm2 - tm1));
}

perf関数のwhile文の中を次のp1, p2, p3のそれぞれの場合についてブラウザ上で測定した。

p1 s = "" + x
p2 s = x + ""
p3 s = String(x)

結果は以下のとおり。

Firefox 3.5.3 Chrome 4.0 Opera 10.0 Safari 4.0.2
p1 3426 1643 12658 2154
p2 3407 1622 11957 2578
p3 3241 1442 13379 3157

ちょっとOperaが遅すぎだが、ブラウザによって傾向が多少異なることがわかる。String関数を使った方が高速なのではないかという私の期待は、FirefoxChromeについてはなんとか成立するが、OperaSafariについては逆効果になっている。なお、IE8.0でも計測しようとしたが、JavaScriptを継続するか中止するかのポップアップが表示されてしまうため、計測できなかった。

同様に文字列を数値に変換する場合、その文字列が正しい数値しか含んでいないと事前に分かる場合には、

var x = +s;

と書かれているコードをしばしば目にする。+は単項演算子である。この場合も、数値に変換する関数Numberを使って、

var x = Number(s);

と書くことができる。前者をq1、後者をq2として、Stringのときと同様の測定をすると、次のようになった。

Firefox 3.5.3 Chrome 4.0 Opera 10.0 Safari 4.0.2
q1 1614 3198 2664 1190
q2 2015 3338 4887 2037

めずらしく、Chromeが遅い結果になったが、どのブラウザも単項演算子(+)を使った方が高速である。

""+xを使って文字列に変換したり、+sを使って数値に変換するのは、どうも気持ち悪いのであるが、パフォーマンスを重視する場合には、一概に悪いとは言えないと認めざるを得ない結果になった。確かに、演算子の方が関数コールより実行効率がよいことは容易に想像がつく。コンパイラがもっと賢くなれば、その差はほとんどなくなると思う。だた、現状、500万回も実行した結果がこの差であり、実際のプログラムではその差の影響はほとんどないと言ってよいと思う。少なくとも、演算子を使った陰な型変換のコードを書く場合にはコメントでその意図を書くべきだろう。そのくらいなら関数を使った陽な型変化の方がやはりよいと思う。どうにも気持ち悪い。

なお、シフト演算子を利用して32ビット整数に変換する手法もあるが、この場合には、対応する関数がないので、シフト演算子を使うという以外に方法はないということを付け加えておく。