Mengapa + begitu buruk untuk penggabungan?

44

Semua orang terus mengatakan bahwa salah satu masalah JavaScript adalah menggunakan +[ contoh ] untuk penggabungan string. Ada yang bilang masalahnya tidak menggunakan +, itu tipe paksaan [lihat komentar dari contoh sebelumnya]. Tetapi bahasa yang diketik dengan kuat menggunakan + untuk jenis penggabungan dan pemaksaan tanpa masalah. Misalnya, dalam C #:

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

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

Jadi mengapa penggabungan string dalam JavaScript adalah masalah besar?

konfigurator
sumber
17
mengapa bad. Siapa Everyone?
Neal
3
Saya pikir masalahnya + adalah operator matematika. Dan bahwa fungsi concatination dari + membingungkan proses standar tersebut. karena sementara "Halo" + nomor mungkin berfungsi + "Halo" mungkin tidak.
SoylentGray
3
@Neal, saya setuju - Saya ingin tahu siapa semua 'orang' mistis ini tampaknya berada dalam semua pertanyaan ini.
GrandmasterB
Menggunakan + untuk concatenation adalah OK. Menggunakan pengetikan dinamis tidak masalah. Menggunakan keduanya dalam bahasa yang sama adalah buruk ^ H ^ H ^ H menyebabkan ambiguitas.
Gerry
6
@Neal - "Semuanya" adalah Douglas Crockford. Dia mencantumkannya "mengerikan" dalam bukunya, 'JavaScript: The Good Parts'.
kirk.burleson

Jawaban:

68

Pertimbangkan kode JavaScript ini:

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

Ini akan masuk

hasilnya adalah 1020

Yang paling mungkin bukan yang dimaksudkan, dan bisa sulit untuk melacak bug.

Mchl
sumber
4
Ilustrasi yang sangat bagus dari masalah yang mendasarinya: penggabungan string tidak terdefinisi dengan baik ketika tipe (string + int + int dalam contoh) dicampur. Lebih baik memiliki operator yang sama sekali berbeda (seperti Perl. '.') Dengan semantik yang terdefinisi dengan baik.
Bruce Ediger
9
Atau cara Python untuk menyelesaikan ini, yang akan memaksa Anda untuk membungkus adan bmasuk str(a)dan str(b)menelepon; jika tidak, Anda mendapatkan ValueError: cannot concatenate 'str' and 'int'.
Aphex
6
@FrustratedWithFormsDesigner: Tambahkan tanda kurung. 'result is ' + (a + b).
Jon Purdy
18
Masalahnya, di C # Anda bisa melakukan hal yang sama, dan Anda akan mendapatkan hasil yang sama - System.Console.WriteLine("result is " + 10 + 20);, tetapi tidak ada yang pernah mengeluh tentang itu di C #. Itu yang saya tidak mengerti - apa tentang JavaScript yang membuatnya lebih membingungkan?
konfigurator
7
@configurator: karena orang diberi tahu C # sempurna dan javascript mengerikan. Mereka berdua salah, tetapi reputasi bahasa tampaknya tetap, persepsi banyak diperhitungkan, terutama pada internet.
gbjbaanb
43

Ketika Anda mengatakan "buruk", apakah yang Anda maksud "salah" atau maksudnya "lambat"? Argumen tentang penggunaan operator matematika untuk melakukan penggabungan string dapat dikatakan sebagai argumen yang "salah", tetapi ada juga argumen yang mengatakan bahwa menggunakan +untuk melakukan banyak penggabungan string bisa sangat lambat.

Kita tidak berbicara tentang "Hello" + numberketika kita berbicara tentang kinerja, kita berbicara tentang membangun string yang relatif besar dengan berulang kali menambahkannya dalam satu lingkaran.

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

Dalam JavaScript (dan C # dalam hal ini) string tidak berubah. Mereka tidak pernah bisa diubah, hanya diganti dengan string lainnya. Anda mungkin sadar bahwa combined + "hello "itu tidak secara langsung memodifikasi combinedvariabel - operasi menciptakan string baru yang merupakan hasil menggabungkan dua string bersama-sama, tetapi Anda kemudian harus menetapkan string baru ke combinedvariabel jika Anda ingin itu diubah.

Jadi apa yang dilakukan loop ini adalah menciptakan jutaan objek string yang berbeda, dan membuang 999.999 darinya. Membuat banyak string yang terus tumbuh dalam ukuran tidak cepat, dan sekarang pengumpul sampah memiliki banyak pekerjaan yang harus dilakukan untuk membersihkan setelah ini.

C # memiliki masalah yang sama persis, yang diselesaikan di lingkungan itu oleh kelas StringBuilder . Dalam JavaScript, Anda akan mendapatkan kinerja yang jauh lebih baik dengan membangun array dari semua string yang ingin Anda gabungkan, dan kemudian bergabung bersama-sama satu kali di akhir, bukannya satu juta kali di loop:

var parts = [];
for (var i = 0; i < 1000000; i++) {
    parts.push("hello");
}
var combined = parts.join(" ");
Joel Mueller
sumber
3
Ini jawaban yang sangat bagus. Tidak hanya menjawab pertanyaan tetapi juga mendidik.
Charles Sprayberry
3
Ini bukan apa yang saya maksudkan sama sekali, itu sama sekali tidak terkait dengan pertanyaan.
konfigurator
4
Maaf. Sepertinya setidaknya 7 orang salah mengerti pertanyaan Anda dari cara kata itu diucapkan.
Joel Mueller
9
Kinerja ulang: Mungkin ini yang terjadi pada tahun 2011, tetapi sekarang metode + operator jauh lebih cepat daripada metode array.join (setidaknya dalam v8). Lihat jsperf ini: jsperf.com/string-concatenation101
UpTheCreek
2
Adakah gagasan bagaimana metode join menghasilkan satu string dari banyak bagian dalam satu langkah, alih-alih juga menggabungkan satu per satu, dengan demikian juga menghasilkan semua string menengah?
Angelo.Hannes
14

Tidak buruk menggunakan + untuk penambahan dan penggabungan, selama Anda hanya dapat menambahkan angka, dan hanya string gabungan. Namun, Javascript akan secara otomatis mengkonversi antara angka dan string sesuai kebutuhan, sehingga Anda memiliki:

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

Mungkin lebih sederhana, kelebihan "+" di hadapan konversi tipe otomatis mematahkan asosiasi yang diharapkan dari operator +:

("x" + 1) + 3 != "x" + (1 + 3)
kevin cline
sumber
2
Juga properti komutatif dari penambahan tidak ada dalam rangkaian 3 + 5 == 5 + 3tetapi"3" + "5" != "5" + "3"
Caleth
10

Masalah khas yang dibawa untuk penggabungan string berkisar pada beberapa masalah:

  1. yang +simbol yang kelebihan beban
  2. kesalahan sederhana
  3. pemrogram menjadi malas

# 1

Masalah pertama dan terpenting dengan penggunaan +untuk penggabungan dan penambahan string adalah bahwa Anda menggunakan +untuk penggabungan dan penambahan string .

jika Anda memiliki variabel adan b, dan Anda mengatur c = a + b, ada ambiguitas tergantung pada jenis adan b. Ambiguitas ini memaksa Anda untuk mengambil langkah-langkah tambahan untuk mengurangi masalah:

String Concat:

c = '' + a + b;

Tambahan:

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

Ini membawa saya ke poin kedua saya

# 2

Sangat mudah untuk secara tidak sengaja melemparkan variabel ke string tanpa menyadarinya. Juga mudah untuk melupakan bahwa input Anda masuk sebagai string:

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

Akan menghasilkan hasil yang tidak intuitif karena prompt mengembalikan nilai string input.

# 3

Perlu mengetik parseFloatatau Number()setiap kali saya ingin melakukan penambahan itu membosankan dan menjengkelkan. Saya menganggap diri saya cukup pintar untuk mengingat tidak mengacaukan tipe dinamis saya, tetapi itu tidak berarti saya tidak pernah mengacaukan tipe dinamis saya . Kebenaran dari masalah ini adalah bahwa saya terlalu malas untuk mengetik parseFloatatau Number()setiap kali saya melakukan penambahan, karena saya melakukan banyak penambahan.

Larutan?

Tidak semua bahasa digunakan +untuk penggabungan string. PHP menggunakan .untuk menggabungkan string, yang membantu membedakan antara kapan Anda ingin menambahkan angka dan kapan Anda ingin bergabung dengan string.

Simbol apa pun dapat digunakan untuk menggabungkan string, tetapi sebagian besar sudah digunakan, dan yang terbaik adalah menghindari duplikasi. Jika saya punya cara saya, saya mungkin akan menggunakan _untuk bergabung dengan string, dan melarang _dalam nama variabel.

zzzzBov
sumber