web-dev-qa-db-ja.com

+はなぜ連結にそんなに悪いのですか?

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

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

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

では、なぜJavaScriptでの文字列連結がそれほど大きな問題なのでしょうか。

44
configurator

次のJavaScriptコードを考えてみましょう。

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

これはログに記録されます

結果は1020です

どちらが意図したものではない可能性が高く、バグの追跡が難しい場合があります。

69
Mchl

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

パフォーマンスについて話すとき、"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では、連結するすべての文字列の配列を作成し、ループ内で100万回ではなく、最後に1回結合することで、パフォーマンスが大幅に向上します。

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

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

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

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

("x" + 1) + 3 != "x" + (1 + 3)
14
kevin cline

文字列の連結で発生する一般的な問題は、いくつかの問題に関係しています。

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

#1

文字列連結に_+_を使用する場合の最初の最も重要な問題and追加は、文字列連結に_+_を使用しているおよび追加。

変数abがあり、_c = a + b_を設定すると、abのタイプに依存するあいまいさが生じます。このあいまいさにより、問題を軽減するために追加の手順を踏む必要があります。

文字列連結:

_c = '' + a + b;
_

添加:

_c = parseFloat(a) + parseFloat(b);
_

これは私に私の第二のポイントをもたらします

#2

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

_a = Prompt('Pick a number');
b = Prompt('Pick a second number');
alert( a + b );
_

Promptは入力の文字列値を返すため、直感的でない結果が生成されます。

#3

追加したいたびにparseFloatまたはNumber()を入力する必要があり、退屈で面倒です。私は自分の動的型を台無しにしないことを覚えておくのに十分賢いと思っていますが、それは動的型を台無しにしたことがないという意味ではありません。問題の真相は、加算を行うたびにparseFloatまたはNumber()を入力するのが面倒なので、大量を加算するためです。

解決?

すべての言語が文字列の連結に_+_を使用するわけではありません。 PHPは_._を使用して文字列を連結します。これは、数値を追加する場合と文字列を結合する場合を区別するのに役立ちます。

文字列を連結するために任意の記号を使用できますが、ほとんどの記号は既に使用されているため、重複を避けるのが最善です。私のやり方があったら、おそらく___を使用して文字列を結合し、変数名に___を使用しないようにします。

10
zzzzBov