Tại sao [1,2] + [3,4] = Hồi 1,23,4 bằng JavaScript?


405

Tôi muốn thêm các phần tử của một mảng vào một mảng khác, vì vậy tôi đã thử điều này:

[1,2] + [3,4]

Nó trả lời với:

"1,23,4"

Chuyện gì đang xảy ra vậy?


1
Đây là một câu hỏi liên quan đến chủ đề này: stackoverflow.com/questions/1724255/why-does-2-2-in-javascript
Xavi

29
Ah-ha-ha, người phỏng vấn tàn bạo có thể hỏi thậm chí một cái gì đó như - điều này sẽ trở lại [1,2] + [5,6,7] [1,2]. tại sao?
shabunc

9
Tôi nghĩ rằng [1,2] + [3,4] đã là biểu hiện được đánh giá cao nhất trong firebird tuần này, sau khi cảnh báo ('tào lao').
okeen

6
Muốn cười không? Hãy thử [] + [], {} + [], {} + {} và [] + {}
Intrepidd

1
@shabunc - quan tâm giải thích tại sao [5,6,7][1,2]7vì nó sử dụng mục cuối cùng trong mảng thứ hai. Oo
vsync

Câu trả lời:


518

Các +nhà điều hành không được định nghĩa cho mảng .

Điều gì xảy ra là Javascript chuyển đổi các mảng thành chuỗi và nối các chuỗi đó.

 

Cập nhật

Vì câu hỏi này và do đó, câu trả lời của tôi đang được chú ý rất nhiều, tôi cảm thấy nó sẽ hữu ích và phù hợp để có cái nhìn tổng quan về cách +hành xử của người vận hành nói chung.

Vì vậy, ở đây nó đi.

Không bao gồm E4X và triển khai cụ thể các công cụ, Javascript (như của ES5) có 6 built-in các kiểu dữ liệu :

  1. Chưa xác định
  2. Vô giá trị
  3. Boolean
  4. Con số
  5. Chuỗi
  6. Vật

Lưu ý rằng mặc dù typeof trả lại một cách khó hiểu object cho Null vàfunction cho các Đối tượng có thể gọi được, Null thực sự không phải là Đối tượng và nói đúng ra, trong các triển khai Javascript tuân thủ đặc tả, tất cả các chức năng đều được coi là Đối tượng.

Điều đó đúng - Javascript không có mảng nguyên thủy như vậy; chỉ các trường hợp của một đối tượng được gọi Arrayvới một số đường cú pháp để giảm đau.

Thêm nhiều hơn vào sự nhầm lẫn, các thực thể của trình bao bọc new Number(5), new Boolean(true)new String("abc")là tất cả các objectloại, không phải là số, booleans hoặc chuỗi như người ta có thể mong đợi. Tuy nhiên, đối với các toán tử số học NumberBooleanhành xử như số.

Dễ chứ hả? Với tất cả những điều đó, chúng ta có thể chuyển sang phần tổng quan.

Các loại kết quả khác nhau của các +loại toán hạng

            || 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 | 

* áp dụng cho Chrome13, FF6, Opera11 và IE9. Kiểm tra các trình duyệt và phiên bản khác là một bài tập cho người đọc.

Lưu ý: Như được chỉ ra bởi CMS , đối với một số trường hợp nhất định của các đối tượng Number, Booleanvà các đối tượng tùy chỉnh, +toán tử không nhất thiết phải tạo ra kết quả chuỗi. Nó có thể thay đổi tùy thuộc vào việc thực hiện đối tượng để chuyển đổi nguyên thủy. Ví dụ: var o = { valueOf:function () { return 4; } };đánh giá o + 2;sản xuất 6, a number, đánh giá o + '2'sản xuất '42', astring .

Để xem bảng tổng quan được tạo như thế nào, hãy truy cập http://jsfiddle.net/1obxuc7m/


244

+Toán tử của JavaScript có hai mục đích: thêm hai số hoặc nối hai chuỗi. Nó không có hành vi cụ thể cho mảng, vì vậy nó chuyển đổi chúng thành chuỗi và sau đó nối chúng.

Nếu bạn muốn tham gia hai mảng để tạo ra một hình mới, sử dụng các .concatphương pháp thay vì:

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

Nếu bạn muốn thêm hiệu quả tất cả các phần tử từ mảng này sang mảng khác, bạn cần sử dụng phương thức .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]

Hành vi của +toán tử được định nghĩa trong ECMA-262 5e Mục 11.6.1 :

11.6.1 Toán tử bổ sung (+)

Toán tử cộng hoặc thực hiện nối chuỗi hoặc cộng số. Việc sản xuất AdditiveExpression : AdditiveExpression + MultiplicativeExpressionđược đánh giá như sau:

  1. Hãy lreflà kết quả của việc đánh giá AdditiveExpression.
  2. Hãy để lvalGetValue(lref).
  3. Hãy rreflà kết quả của việc đánh giá MultiplicativeExpression.
  4. Hãy để rvalGetValue(rref).
  5. Hãy để lprimToPrimitive(lval).
  6. Hãy để rprimToPrimitive(rval).
  7. Nếu Type(lprim)Stringhoặc Type(rprim)String, thì
    1. Trả về Chuỗi là kết quả của việc nối ToString(lprim)tiếp theo sauToString(rprim)
  8. Trả về kết quả của việc áp dụng các hoạt động bổ sung cho ToNumber(lprim)ToNumber(rprim). Xem chú thích bên dưới 11.6.3.

Bạn có thể thấy rằng mỗi toán hạng được chuyển đổi ToPrimitive. Bằng cách đọc thêm chúng ta có thể thấy rằng ToPrimitivesẽ luôn chuyển đổi các mảng thành chuỗi, tạo ra kết quả này.


7
+1 vì câu trả lời này không chỉ giải thích vấn đề mà còn giải thích cách thực hiện đúng.
schnaader

3
Có một chút tmi ở đây, nhưng tôi đồng ý với schnaader. Các câu trả lời tốt nhất giải thích vấn đề / lỗi / hành vi đang được hỏi sau đó cho thấy cách tạo ra kết quả dự định. +1
matthewdunnam

1
Tại sao bạn sẽ sử dụng dài dòng hơn Array.prototype.push.apply(data, [3, 4])thay vì data.concat([3,4])?
evilcelery

5
@evilcelery: Họ phục vụ các mục đích khác nhau. concattạo ra một Mảng mới , cuộc gọi dài hơn có hiệu quả mở rộng một Mảng hiện có .
Jeremy Banks

1
Bạn có thể sử dụng [].push.apply(data, [3,4])cho độ dài ít hơn một chút. Ngoài ra, điều đó được đảm bảo để chống lại những người khác thay đổi giá trị của Array.
Sam Tobin-Hochstadt

43

Nó thêm hai mảng như thể chúng là các chuỗi .

Biểu diễn chuỗi cho mảng đầu tiên sẽ là "1,2" và chuỗi thứ hai sẽ là "3,4" . Vì vậy, khi +tìm thấy dấu hiệu, nó không thể tính tổng các mảng và sau đó ghép chúng thành các chuỗi.


Vâng, đó là lời giải thích đầu tiên và duy nhất đến với tâm trí, nhưng đó không phải là một hành vi rất kỳ lạ sao? có thể có một số thao tác / chuyển đổi không rõ ràng đang được thực hiện và tôi rất muốn biết những người tham gia: P
okeen

40

Các +chuỗi concats, do đó, nó chuyển đổi các mảng thành chuỗi.

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

Để kết hợp mảng, sử dụng concat.

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

21

Trong JavaScript, toán tử cộng nhị phân ( +) thực hiện cả phép cộng số và nối chuỗi. Tuy nhiên, khi đối số đầu tiên của nó không phải là một số cũng không phải là một chuỗi thì nó sẽ chuyển đổi nó thành một chuỗi (do đó " 1,2"), sau đó nó làm tương tự với "" thứ hai 3,4và nối chúng thành " 1,23,4".

Thay vào đó, hãy thử sử dụng phương pháp "concat" của Mảng:

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

19

Đó là chuyển đổi các mảng riêng lẻ thành chuỗi, sau đó kết hợp các chuỗi.


14

Có vẻ như JavaScript đang biến các mảng của bạn thành các chuỗi và nối chúng lại với nhau. Nếu bạn muốn thêm các bộ dữ liệu với nhau, bạn sẽ phải sử dụng một vòng lặp hoặc chức năng bản đồ.


14

[1,2]+[3,4] trong JavaScript cũng giống như đánh giá:

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

và vì vậy để giải quyết vấn đề của bạn, điều tốt nhất là thêm hai mảng tại chỗ hoặc không tạo một mảng mới:

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

12

Đó là làm chính xác những gì bạn yêu cầu nó làm.

Những gì bạn đang thêm vào là các tham chiếu mảng (mà JS chuyển đổi thành chuỗi), không phải là số như có vẻ. Nó hơi giống như thêm các chuỗi lại với nhau: "hello " + "world"="hello world"


5
hehe, nó luôn luôn làm những gì tôi yêu cầu Vấn đề là đặt câu hỏi hay. Điều khiến tôi tò mò là cách giải thích toString () của các mảng khi bạn thêm chúng.
okeen


8

Đó là bởi vì, toán tử + giả định rằng các toán hạng là chuỗi, nếu chúng không phải là số. Vì vậy, trước tiên, nó chuyển đổi chúng thành chuỗi và concats để đưa ra kết quả cuối cùng, nếu đó không phải là một số. Ngoài ra, nó không hỗ trợ mảng.


2
Toán tử + KHÔNG thể giả sử toán hạng là các chuỗi, vì 1 + 1 == 2, trong số các toán tử khác. Đó là vì '+' không được xác định cho các mảng, do đó, nó sẽ tạo ra chúng.
okeen

0

Một số câu trả lời ở đây đã giải thích làm thế nào đầu ra không mong muốn ( '1,23,4') không mong muốn xảy ra và một số đã giải thích làm thế nào để có được cái mà họ cho là đầu ra mong muốn ( [1,2,3,4]), nghĩa là nối mảng. Tuy nhiên, bản chất của đầu ra mong muốn thực sự hơi mơ hồ vì câu hỏi ban đầu chỉ đơn giản là "Tôi muốn thêm các phần tử của một mảng vào một ...". Điều đó có thể có nghĩa là nối mảng nhưng cũng có thể có nghĩa là bổ sung tuple (ví dụ ở đâyở đây ), nghĩa là thêm các giá trị vô hướng của các phần tử trong một mảng vào các giá trị vô hướng của các phần tử tương ứng trong phần thứ hai, ví dụ: kết hợp [1,2][3,4]thu được[4,6] .

Giả sử cả hai mảng có cùng độ dài / độ dài, đây là một giải pháp đơn giản:

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]


-1

Một kết quả khác chỉ sử dụng dấu "+" đơn giản sẽ là:

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

Vì vậy, một cái gì đó như thế này sẽ hoạt động (nhưng!):

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

... nhưng nó sẽ chuyển đổi biến a từ Mảng thành Chuỗi! Hãy ghi nhớ nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.