Dlaczego [1,2] + [3,4] = „1,23,4” w JavaScript?


405

Chciałem dodać elementy tablicy do innego, więc spróbowałem:

[1,2] + [3,4]

Odpowiedział:

"1,23,4"

Co się dzieje?



29
Ah-ha-ha, sadysta przesłuchujący może zapytać nawet coś takiego - co to zwróci [1,2] + [5,6,7] [1,2]. dlaczego?
shabunc

9
Myślę, że [1,2] + [3,4] to najbardziej oceniane wyrażenie w Firebug w tym tygodniu, po alarmie („bzdura”).
okeen

6
Chcesz się pośmiać ? Spróbuj [] + [], {} + [], {} + {} i [] + {}
Intrepidd

1
@shabunc - troska o wyjaśnienie, dlaczego [5,6,7][1,2]jest 7, ponieważ używa ostatni element w drugiej tablicy. Oo
vsync,

Odpowiedzi:


518

+Operator nie jest zdefiniowany dla tablic .

Dzieje się tak, że JavaScript konwertuje tablice na ciągi i łączy je.

 

Aktualizacja

Ponieważ na to pytanie i w związku z tym moją odpowiedź zyskuje wiele uwagi, uznałem, że użyteczne i odpowiednie byłoby posiadanie przeglądu tego, jak +ogólnie zachowuje się operator.

A więc proszę bardzo.

Z wyjątkiem E4X i specyficznych dla implementacji rzeczy, Javascript (od ES5) ma 6 wbudowanych typów danych :

  1. Nieokreślony
  2. Zero
  3. Boolean
  4. Numer
  5. Strunowy
  6. Obiekt

Zwróć uwagę, że chociaż typeof nieco myląco zwraca wartość object Null i functionObiekty, które można wywoływać, Null w rzeczywistości nie jest Obiektem, a ściśle mówiąc, w implementacjach Javascript zgodnych ze specyfikacją wszystkie funkcje są uważane za Obiekty.

Zgadza się - JavaScript nie ma prymitywnych tablic jako takich; tylko instancje obiektu wywoływane Arrayz cukrem składniowym w celu złagodzenia bólu.

Dodając do zamieszania, wrapper podmiotów, takich jak new Number(5), new Boolean(true)i new String("abc")wszystkie są objecttypu, a nie liczby, wartości logiczne lub strun, jak można by oczekiwać. Niemniej dla operatorów arytmetycznych Numberi Booleanzachowywać się jak liczby.

Łatwe, co? Po tym wszystkim możemy przejść do samego przeglądu.

Różne typy wyników +według typów operandów

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

* dotyczy Chrome13, FF6, Opera11 i IE9. Sprawdzanie innych przeglądarek i wersji pozostawia się jako ćwiczenie dla czytelnika.

Uwaga: Jak podkreślił CMS dla pewnych przypadkach obiektów takich jak Number, Booleani niestandardowych te z +operator nie musi produkować wynik ciąg. Może się różnić w zależności od implementacji konwersji obiektu na pierwotną. Na przykład var o = { valueOf:function () { return 4; } };oceny o + 2;produkuje 6, A number, oceny o + '2'produkuje '42', A string.

Aby zobaczyć, jak wygenerowano tabelę przeglądów, odwiedź http://jsfiddle.net/1obxuc7m/


244

+Operator JavaScript ma dwa cele: dodanie dwóch liczb lub połączenie dwóch ciągów. Nie ma określonego zachowania dla tablic, więc konwertuje je na ciągi, a następnie łączy je.

Jeśli chcesz dołączyć do dwóch tablic do produkcji nowego, skorzystać z .concatmetody zamiast:

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

Jeśli chcesz efektywnie dodać wszystkie elementy z jednej tablicy do drugiej, musisz użyć metody .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]

Zachowanie +operatora jest zdefiniowane w ECMA-262 5e sekcja 11.6.1 :

11.6.1 Operator dodawania (+)

Operator dodawania dokonuje konkatenacji łańcucha lub dodawania liczbowego. Produkcja AdditiveExpression : AdditiveExpression + MultiplicativeExpressionjest oceniana w następujący sposób:

  1. Pozwól lrefbyć wynikiem oceny AdditiveExpression.
  2. Niech lvalbędzie GetValue(lref).
  3. Pozwól rrefbyć wynikiem oceny MultiplicativeExpression.
  4. Niech rvalbędzie GetValue(rref).
  5. Niech lprimbędzie ToPrimitive(lval).
  6. Niech rprimbędzie ToPrimitive(rval).
  7. Jeśli Type(lprim)jest Stringlub Type(rprim)jest String, to
    1. Zwraca ciąg będący wynikiem konkatenacji, ToString(lprim)po którym następujeToString(rprim)
  8. Zwróć wynik zastosowania operacji dodawania do ToNumber(lprim)i ToNumber(rprim). Uwaga poniżej 11.6.3.

Widać, że każdy operand jest konwertowany ToPrimitive. Czytając dalej, możemy przekonać się, że ToPrimitivezawsze konwertuje tablice na ciągi, wytwarzając ten wynik.


7
+1, ponieważ ta odpowiedź nie tylko wyjaśnia problem, ale także wyjaśnia, jak zrobić to dobrze.
schnaader,

3
jest tu trochę tmi, ale zgadzam się ze schnaaderem. Najlepsze odpowiedzi wyjaśniają problem / błąd / zachowanie, o które się pytają, a następnie pokazują, jak uzyskać zamierzony rezultat. +1
matthewdunnam

1
Dlaczego miałbyś używać bardziej szczegółowego Array.prototype.push.apply(data, [3, 4])zamiast data.concat([3,4])?
evilcelery

5
@evilcelery: Służą do różnych celów. concattworzy nową macierz, dłuższe wywołanie skutecznie rozszerza istniejącą macierz.
Jeremy Banks,

1
Możesz użyć [].push.apply(data, [3,4])dla nieco mniej gadatliwości. Gwarantuje to również, że będzie odporny na zmiany wartości innych osób Array.
Sam Tobin-Hochstadt,

43

Dodaje dwie tablice, jakby były łańcuchami .

Reprezentacja ciągu dla pierwszej tablicy to „1,2”, a druga to „3,4” . Kiedy więc +znak zostanie znaleziony, nie może sumować tablic, a następnie konkatenować je jako ciągi znaków.


Tak, to pierwsze i unikalne wyjaśnienie, które przychodzi do głowy, ale czy to nie jest dziwne zachowanie? może jest jakaś mroczna, nieznana operacja / transformacja, a chciałbym poznać wewnętrzne: P
okeen

40

W +concats struny, więc przekształca tablic do strun.

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

Aby połączyć tablice, użyj concat.

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

21

W JavaScript operator dodawania binarnego ( +) wykonuje zarówno dodawanie numeryczne, jak i konkatenację ciągów. Jeśli jednak pierwszym argumentem nie jest ani liczba, ani ciąg, konwertuje go na ciąg (stąd „ 1,2”), a następnie robi to samo z drugim „ 3,4” i łączy je w „1,23,4 ”.

Zamiast tego spróbuj użyć metody „concat” tablic:

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

19

Konwertuje poszczególne tablice na ciągi, a następnie łączy je.


14

Wygląda na to, że JavaScript zamienia tablice w ciągi znaków i łączy je ze sobą. Jeśli chcesz dodać krotki razem, musisz użyć pętli lub funkcji mapy.


14

[1,2]+[3,4] w JavaScript to samo, co ocena:

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

więc aby rozwiązać problem, najlepiej byłoby dodać dwie tablice na miejscu lub bez tworzenia nowej tablicy:

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

12

Robi dokładnie to, o co go prosiłeś.

To, co dodajesz razem, to odwołania do tablicy (które JS konwertuje na ciągi), a nie liczby, jak się wydaje. To trochę jak dodawanie ciągów razem: "hello " + "world"="hello world"


5
hehe, ZAWSZE robi to, o co prosiłem. Problem polega na zadaniu dobrego pytania. Intryguje mnie interpretacja tablic toString () podczas ich dodawania.
okeen


8

Wynika to z faktu, że operator + zakłada, że ​​operandy są łańcuchami, jeśli nie są liczbami. Najpierw konwertuje je na ciągi znaków i konkataty, aby uzyskać końcowy wynik, jeśli nie jest liczbą. Ponadto nie obsługuje tablic.


2
Operator + NIE może zakładać, że operandy są łańcuchami, ponieważ między 1 + 1 == 2. Wynika to z faktu, że „+” nie jest zdefiniowane dla tablic, więc to je ciągnie.
okeen

0

Niektóre odpowiedzi wyjaśniają, w jaki sposób '1,23,4'dzieje się nieoczekiwane niepożądane wyjście ( ), a niektóre wyjaśniają, w jaki sposób uzyskać zakładane oczekiwane wyjście ( [1,2,3,4]), tj. Konkatenację macierzy. Jednak natura oczekiwanego pożądanego wyniku jest w rzeczywistości nieco niejednoznaczna, ponieważ pierwotne pytanie brzmi po prostu: „Chciałem dodać elementy tablicy do innego ...”. To może oznaczać tablicy konkatenacji ale może również średnią dodanie krotny (np tu i tu ), czyli dodanie skalarne wartości elementów w jednej tablicy do skalarnych wartości odpowiadających im elementów na sekundę, na przykład łączenie [1,2]i [3,4]uzyskać [4,6].

Zakładając, że obie tablice mają tę samą aryczność / długość, oto jedno proste rozwiązanie:

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

Kolejnym wynikiem przy użyciu prostego znaku „+” będzie:

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

Więc coś takiego powinno działać (ale!):

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

... ale przekształci zmienną a z tablicy na łańcuch! Pamiętaj o tym.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.