なぜ+は連結にとってそれほど悪いのですか?


44

JavaScriptの問題の1つは、文字列の連結に+[ ]を使用しているということです。問題はを使用していないと言う人もいますが+、それは型強制です(前の例のコメントを参照)。ただし、厳密に型指定された言語では、連結と強制型に問題なく+を使用します。たとえば、C#の場合:

int number = 1;
MyObject obj = new MyObject();

var result = "Hello" + number + obj;
// is equivalent to
string result = "hello" + number.ToString() + obj.ToString();

では、なぜJavaScriptでの文字列の連結がそんなに大きな問題なのでしょうか?


17
なぜですかbad。誰Everyoneですか?
ニール

3
問題は+は数学的な演算子だと思います。そして、+の連結関数は、その標準プロセスを混乱させます。「Hello」+数字は機能するかもしれないが、number +「Hello」は機能しないかもしれないから
-SoylentGray

3
@ニール、私は同意します-これらすべての神秘的な「全員」がこれらすべての質問に誰がいるのかを知りたいです。
GrandmasterB

連結に+を使用しても問題ありません。動的型付けを使用しても問題ありません。同じ言語で両方を使用するのは良くありません^ H ^ H ^ Hはあいまいさをもたらします。
ジェリー

6
@ニール-「みんな」はダグラス・クロックフォードでしょう。彼はそれを彼の本の「JavaScript:The Good Parts」に「ひどい」と記載しています。
kirk.burleson

回答:


68

次のJavaScriptコードを検討してください。

var a = 10;
var b = 20;
console.log('result is ' + a + b);

これはログに記録します

結果は1020

これはおそらく意図したものではなく、バグを追跡するのが難しい可能性があります。


4
根本的な問題の非常に素晴らしい図解:型(例ではstring + int + int)が混在する場合、文字列の連結は明確に定義されていません。セマンティクスが明確に定義された完全に異なる演算子(Perlの '。'など)を持つ方が良い。
ブルースエディガー

9
または、これを解決するPythonの方法は、ラップaアンドbインstr(a)str(b)呼び出しを強制することです。それ以外の場合は、を取得しValueError: cannot concatenate 'str' and 'int'ます。
エイフェックス・

6
@FrustratedWithFormsDesigner:括弧を追加します。'result is ' + (a + b)
ジョンパーディ

18
C#では同じことができ、同じ結果が得られます- System.Console.WriteLine("result is " + 10 + 20);ですが、C#でそれについて文句を言う人はいません。それは私が理解していないことです-JavaScriptをもっと混乱させているのはなぜですか?
コンフィギュレー

7
@configurator:C#は完璧であり、javascriptはひどいと言われているからです。どちらも間違っていますが、言語の評判は固まっているようで、特にインターネットでは認識が非常に重要です。
gbjbaanb

43

「悪い」と言うとき、「間違っている」という意味ですか、それとも「遅い」という意味ですか?文字列の連結を行うために数学演算子を使用することに関する議論は間違いなく「間違った」引数+ですが、多くの文字列の連結を行うために使用すると非常に遅くなる可能性があるという議論もあります。

"Hello" + numberパフォーマンスについて話すときではなく、ループに繰り返し追加することで比較的大きな文字列を構築することについて話しています。

var combined = "";
for (var i = 0; i < 1000000; i++) {
    combined = combined + "hello ";
}

JavaScript(およびそれに関するC#)では、文字列は不変です。変更することはできず、他の文字列に置き換えるだけです。おそらく変数をcombined + "hello "直接変更しないことをご存知でしょうcombined-操作は2つの文字列を連結した結果である新しい文字列を作成しますが、combined変更したい場合はその新しい文字列を変数に割り当てる必要があります。

したがって、このループが行っているのは、100万の異なる文字列オブジェクトを作成し、それらを999,999個捨てることです。継続的にサイズが大きくなるほど多くの文字列を作成することは高速ではなく、ガベージコレクターはこの後クリーンアップするために多くの作業を行う必要があります。

C#にはまったく同じ問題があり、その環境ではStringBuilderクラスによって解決されます。JavaScriptでは、連結するすべての文字列の配列を構築し、ループ内で数百万回ではなく、最後に一度結合することにより、パフォーマンスが大幅に向上します。

var parts = [];
for (var i = 0; i < 1000000; i++) {
    parts.push("hello");
}
var combined = parts.join(" ");

3
これは素晴らしい答えです。質問に答えただけでなく、教育も受けました。
チャールズスプレーベリー

3
ただし、これは私が意図したものではありません。質問とはまったく関係ありません。
コンフィギュレー

4
ごめんなさい。少なくとも7人が、あなたの質問を言葉どおりに誤解したようです。
ジョエルミューラー

9
パフォーマンスに関して:たぶん2011年にはそうだったかもしれませんが、今では+演算子メソッドはarray.joinメソッドよりもはるかに高速です(少なくともv8では)。このjsperfを参照してください:jsperf.com/string-concatenation101
UpTheCreek

2
結合方法が複数の部分から1つの文字列を1つのステップで生成する方法を考えています。
アンジェロハネス14年

14

数字のみを追加でき、文字列のみを連結できる限り、加算と連結の両方に+を使用することは悪くありません。ただし、Javascriptは必要に応じて数字と文字列を自動的に変換するため、次のことができます。

3 * 5 => 15
"3" * "5" => 15
2 + " fish" => "2 fish"
"3" + "5" => "35"  // hmmm...

おそらくもっと簡単に、自動型変換の存在下で「+」をオーバーロードすると、予想される+演算子の結合性が壊れます。

("x" + 1) + 3 != "x" + (1 + 3)

2
また、加算の可3 + 5 == 5 + 3"3" + "5" != "5" + "3"
換特

10

文字列の連結で発生する典型的な問題は、いくつかの問題を中心に展開されます。

  1. +オーバーロードされているシンボル
  2. 単純な間違い
  3. 怠beingなプログラマー

#1

使用して、何よりもまず、問題+の文字列の連結のためにほかは、あなたが使用していることである+文字列の連結のために追加。

変数がaありb、設定している場合、とc = a + bのタイプに依存するあいまいさがaありbます。このあいまいさにより、問題を軽減するために追加の手順を実行する必要があります。

文字列連結:

c = '' + a + b;

添加:

c = parseFloat(a) + parseFloat(b);

これは私の2番目のポイントに私をもたらします

#2

気付かないうちに誤って変数を文字列にキャストするのは非常に簡単です。入力が文字列として入力されることも忘れがちです。

a = prompt('Pick a number');
b = prompt('Pick a second number');
alert( a + b );

プロンプトは入力の文字列値を返すため、直感的でない結果を生成します。

#3

入力する必要があるparseFloatNumber()、追加するたびに面倒で面倒です。私は自分が動的型を台無しにしないことを覚えているほど頭がいいと思いますが、それ動的型を台無しにしたことがないという意味はありません。問題の真実は、入力するのが面倒だということ、parseFloatまたはNumber()追加を行うたびに、私は多くの追加を行うためです。

解決?

すべての言語+が文字列の連結に使用するわけではありません。PHPは.、文字列を連結するために使用します。これにより、いつ数字を追加するか、いつ文字列を結合するかを区別できます。

任意のシンボルを使用して文字列を連結できますが、ほとんどはすでに使用されているため、重複を避けるのが最善です。方法があれば、おそらく_文字列を結合するために使用し、_in変数名を許可しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.