Mengapa [1,2] + [3,4] = “1,23,4” dalam JavaScript?

405

Saya ingin menambahkan elemen array ke yang lain, jadi saya mencoba ini:

[1,2] + [3,4]

Itu merespons dengan:

"1,23,4"

Apa yang sedang terjadi?

okeen
sumber
1
Berikut pertanyaan yang terkait dengan topik ini: stackoverflow.com/questions/1724255/why-does-2-2-in-javascript
Xavi
29
Ah-ha-ha, pewawancara sadis dapat bertanya bahkan sesuatu seperti - apa ini akan kembali [1,2] + [5,6,7] [1,2]. Mengapa?
shabunc
9
Saya pikir [1,2] + [3,4] telah menjadi ekspresi yang paling dievaluasi di pembakar minggu ini, setelah peringatan ('omong kosong').
okeen
6
Mau tertawa ? Coba [] + [], {} + [], {} + {}, dan [] + {}
Intrepidd
1
@shabunc - hati untuk menjelaskan mengapa [5,6,7][1,2]adalah 7karena menggunakan item terakhir dalam array kedua. Oo
vsync

Jawaban:

518

The +Operator tidak didefinisikan untuk array .

Yang terjadi adalah Javascript mengubah array menjadi string dan menggabungkannya.

 

Memperbarui

Karena pertanyaan ini dan akibatnya jawaban saya mendapatkan banyak perhatian, saya merasa akan bermanfaat dan relevan untuk memiliki gambaran umum tentang bagaimana +operator berperilaku secara umum juga.

Jadi begini saja.

Tidak termasuk E4X dan hal-hal implementasi khusus, Javascript (per ES5) memiliki 6 built-in tipe data :

  1. Tidak terdefinisi
  2. Batal
  3. Boolean
  4. Jumlah
  5. Tali
  6. Obyek

Perhatikan bahwa meskipun typeof agak membingungkan object untuk Null danfunction untuk Obyek yang bisa dipanggil, Null sebenarnya bukan Obyek dan secara tegas, dalam implementasi Javascript yang sesuai spesifikasi semua fungsi dianggap sebagai Objek.

Itu benar - Javascript tidak memiliki array primitif seperti itu; hanya contoh dari Obyek yang disebut Arraydengan gula sintaksis untuk meringankan rasa sakit.

Menambah lebih banyak kebingungan, entitas pembungkus seperti new Number(5), new Boolean(true)dan new String("abc")semuanya objectbertipe, bukan angka, boolean atau string seperti yang mungkin diharapkan. Meskipun demikian untuk operator aritmatika Numberdan Booleanberperilaku sebagai angka.

Mudah kan? Dengan semua itu, kita bisa beralih ke ikhtisar itu sendiri.

Jenis hasil yang berbeda dari +jenis operan

            || undefined | null   | boolean | number | string | object |
=========================================================================
 undefined  || number    | number | number  | number | string | string | 
 null       || number    | number | number  | number | string | string | 
 boolean    || number    | number | number  | number | string | string | 
 number     || number    | number | number  | number | string | string | 
 string     || string    | string | string  | string | string | string | 
 object     || string    | string | string  | string | string | string | 

* berlaku untuk Chrome13, FF6, Opera11 dan IE9. Memeriksa browser dan versi lain dibiarkan sebagai latihan untuk pembaca.

Catatan: Seperti yang ditunjukkan oleh CMS , untuk kasus tertentu objek seperti Number, Booleandan yang khusus, +operator tidak harus menghasilkan hasil string. Ini dapat bervariasi tergantung pada implementasi objek ke konversi primitif. Sebagai contohvar o = { valueOf:function () { return 4; } }; mengevaluasi o + 2;menghasilkan 6, sebuah number, mengevaluasi o + '2'menghasilkan '42', sebuah string.

Untuk melihat bagaimana tabel ikhtisar dihasilkan kunjungan http://jsfiddle.net/1obxuc7m/

Saulus
sumber
244

JavaScript + memiliki dua tujuan: menambahkan dua angka, atau menggabungkan dua string. Itu tidak memiliki perilaku spesifik untuk array, jadi itu mengubah mereka menjadi string dan kemudian bergabung dengan mereka.

Jika Anda ingin bergabung dua array untuk menghasilkan yang baru, menggunakan yang .concatmetode sebagai gantinya:

[1, 2].concat([3, 4]) // [1, 2, 3, 4]

Jika Anda ingin secara efisien menambahkan semua elemen dari satu array ke array lainnya, Anda perlu menggunakan metode .push :

var data = [1, 2];

// ES6+:
data.push(...[3, 4]);
// or legacy:
Array.prototype.push.apply(data, [3, 4]);

// data is now [1, 2, 3, 4]

Perilaku +operator didefinisikan dalam ECMA-262 5e Bagian 11.6.1 :

11.6.1 Operator Penambahan (+)

Operator tambahan melakukan penggabungan string atau penambahan numerik. Produksi AdditiveExpression : AdditiveExpression + MultiplicativeExpressiondievaluasi sebagai berikut:

  1. Biarkan lrefmenjadi hasil evaluasiAdditiveExpression.
  2. Biarkan lvalsajaGetValue(lref).
  3. Biarkan rrefmenjadi hasil evaluasi MultiplicativeExpression.
  4. Biarkan rvalsaja GetValue(rref).
  5. Biarkan lprimsaja ToPrimitive(lval).
  6. Biarkan rprimsaja ToPrimitive(rval).
  7. Jika Type(lprim)ada Stringatau Type(rprim)tidak String, maka
    1. Kembalikan String yang merupakan hasil penggabungan ToString(lprim)diikuti olehToString(rprim)
  8. Kembalikan hasil penerapan operasi penambahan ke ToNumber(lprim)dan ToNumber(rprim). Lihat Catatan di bawah 11.6.3.

Anda dapat melihat bahwa setiap operan dikonversi ToPrimitive. Dengan membaca lebih lanjut kita dapat menemukan bahwa ToPrimitivearray akan selalu dikonversi ke string, menghasilkan hasil ini.

Jeremy Banks
sumber
7
Memberi +1 sebagai jawaban ini tidak hanya menjelaskan masalah, tetapi juga menjelaskan cara melakukannya dengan benar.
schnaader
3
ada tmi kecil di sini, tapi saya setuju dengan schnaader. Jawaban terbaik menjelaskan masalah / kesalahan / perilaku yang ditanyakan kemudian menunjukkan bagaimana menghasilkan hasil yang diinginkan. +1
matthewdunnam
1
Mengapa Anda menggunakan lebih banyak verbose Array.prototype.push.apply(data, [3, 4])alih-alih data.concat([3,4])?
evilcelery
5
@ evilcelery: Mereka melayani tujuan yang berbeda. concatmenghasilkan Array baru , semakin lama panggilan efisien memperpanjang Array yang ada .
Jeremy Banks
1
Anda bisa menggunakan kata [].push.apply(data, [3,4])-kata yang sedikit kurang. Juga, yang dijamin tahan terhadap orang lain mengubah nilai Array.
Sam Tobin-Hochstadt
43

Ini menambahkan dua array seolah-olah mereka adalah string .

Representasi string untuk array pertama adalah "1,2" dan yang kedua adalah "3,4" . Jadi ketika +tanda ditemukan, itu tidak bisa menjumlahkan array dan kemudian menggabungkannya sebagai string.

Doug
sumber
Ya, itu adalah penjelasan pertama dan unik yang muncul di pikiran tetapi, bukankah itu perilaku yang sangat aneh? mungkin ada beberapa yang gelap, operasi / transformasi yang tidak diketahui sedang dilakukan, dan saya ingin tahu inner: P
okeen
40

The +concats string, sehingga mengubah array ke string.

[1,2] + [3,4]
'1,2' + '3,4'
1,23,4

Untuk menggabungkan array, gunakan concat.

[1,2].concat([3,4])
[1,2,3,4]
Roket Hazmat
sumber
21

Dalam JavaScript, operator penambahan biner ( +) melakukan penambahan numerik dan penggabungan string. Namun, ketika argumen pertama bukan angka atau string maka itu mengubahnya menjadi string (karenanya " 1,2") maka ia melakukan hal yang sama dengan yang kedua " 3,4" dan menyatukan mereka menjadi " 1,23,4".

Coba gunakan metode "concat" dari Arays:

var a = [1, 2];
var b = [3, 4];
a.concat(b) ; // => [1, 2, 3, 4];
maerics
sumber
19

Ini mengubah array individu menjadi string, kemudian menggabungkan string.

anak laki-laki
sumber
14

Sepertinya JavaScript mengubah array Anda menjadi string dan menggabungkannya. Jika Anda ingin menambahkan tupel bersama, Anda harus menggunakan fungsi lingkaran atau peta.

Adam Fabicki
sumber
14

[1,2]+[3,4] dalam JavaScript sama dengan mengevaluasi:

new Array( [1,2] ).toString() + new Array( [3,4] ).toString();

dan untuk mengatasi masalah Anda, hal terbaik adalah menambahkan dua array di tempat atau tanpa membuat array baru:

var a=[1,2];
var b=[3,4];
a.push.apply(a, b);
pengguna286806
sumber
12

Itu melakukan persis seperti yang Anda minta.

Apa yang Anda tambahkan bersama adalah referensi array (yang dikonversi JS ke string), bukan angka seperti yang terlihat. Ini agak seperti menambahkan string bersama: "hello " + "world"="hello world"

Jamie Dixon
sumber
5
hehe, SELALU melakukan apa yang saya minta. Masalahnya adalah mengajukan pertanyaan yang bagus. Yang membuat saya penasaran adalah interpretasi toString () dari array ketika Anda menambahkannya.
okeen
8

Itu karena, + operator mengasumsikan bahwa operan adalah string, jika bukan angka. Jadi, pertama-tama mengubahnya menjadi string dan concats untuk memberikan hasil akhir, jika bukan angka. Juga, itu tidak mendukung array.

Prashant Singh
sumber
2
Operator + TIDAK dapat menganggap operan adalah string, karena 1 + 1 == 2, antara lain. Itu karena '+' tidak didefinisikan untuk array, jadi toString-s mereka.
okeen
0

Beberapa jawaban di sini telah menjelaskan bagaimana output yang tidak diinginkan yang tidak diharapkan ( '1,23,4') terjadi dan beberapa telah menjelaskan bagaimana mendapatkan apa yang mereka anggap sebagai output yang diinginkan ( [1,2,3,4]), yaitu array concatenation. Namun, sifat dari output yang diinginkan sebenarnya agak ambigu karena pertanyaan aslinya hanya menyatakan "Saya ingin menambahkan elemen-elemen dari array ke yang lain ...". Itu bisa berarti array array tetapi juga bisa berarti penambahan tuple (misalnya di sini dan di sini ), yaitu menambahkan nilai skalar elemen dalam satu array ke nilai skalar elemen yang sesuai di elemen kedua, misalnya menggabungkan [1,2]dan [3,4]mendapatkan [4,6].

Dengan asumsi kedua array memiliki arity / panjang yang sama, berikut adalah satu solusi sederhana:

const arr1 = [1, 2];
const arr2 = [3, 4];

const add = (a1, a2) => a1.map((e, i) => e + a2[i]);

console.log(add(arr1, arr2)); // ==> [4, 6]

Andrew Willems
sumber
-1

Hasil lain hanya dengan menggunakan tanda "+" sederhana adalah:

[1,2]+','+[3,4] === [1,2,3,4]

Jadi sesuatu seperti ini seharusnya bekerja (tapi!):

var a=[1,2];
var b=[3,4];
a=a+','+b; // [1,2,3,4]

... tetapi itu akan mengubah variabel dari Array ke String! Ingatlah itu.

Bincul hitam
sumber