Dlaczego jest [1,2] + [3,4] = "1,23,4" w JavaScript?

Chciałem dodać elementy tablicy do innej, więc próbowałem tego:

[1,2] + [3,4]

Odpowiedziało:

"1,23,4"
Co się dzieje?
Author: Sнаđошƒаӽ, 2011-08-19

13 answers

Operator + nie jest zdefiniowany dla tablic.

Dzieje się tak, że Javascript konwertuje tablice na ciągi znaków i łączy je.

 

Update

Ponieważ to pytanie i w związku z tym moja odpowiedź jest coraz dużo uwagi, uznałem, że byłoby przydatne i istotne, aby mieć przegląd o tym, jak operator + zachowuje się ogólnie.

/ Align = "left" /

Z wyłączeniem E4X i specyficznych dla implementacji rzeczy, Javascript (od ES5) ma 6 wbudowane typy danych :

  1. Undefined
  2. Null
  3. Boolean
  4. Liczba
  5. String
  6. obiekt

Zauważ, że chociaż typeof nieco mylnie powraca object dla obiektów null i function, Null nie jest w rzeczywistości obiektem i ściśle mówiąc, w implementacjach Javascript zgodnych ze specyfikacją wszystkie funkcje są uważane za przedmioty.

To prawda - Javascript nie ma żadnych prymitywnych tablic jako takich; tylko instancje obiektu o nazwie Array z odrobiną cukru składniowego, aby złagodzić ból.

Dodając więcej do zamieszania, encje wrappera, takie jak new Number(5), new Boolean(true) i {[9] } to wszystkie typy object, a nie liczby, booleany lub łańcuchy, jak można się spodziewać. Niemniej jednak operatory arytmetyczne Number i Boolean zachowują się jak liczby.

Spokojnie, co? Z tym wszystkim, możemy przejdź 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 jest pozostawione jako ćwiczenie dla czytelnika.

Uwaga: jak wskazuje CMS , dla niektórych przypadków obiektów takich jak Number, Boolean i niestandardowe operator + niekoniecznie generuje wynik Łańcuchowy. Może się różnić w zależności od implementacja obiektu do prymitywnej konwersji. Na przykład var o = { valueOf:function () { return 4; } }; ocena o + 2; produkuje 6, a number, ocena o + '2' produkuje '42', a string.

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

 499
Author: Saul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:50

Operator JavaScript + ma dwa cele: dodawanie dwóch liczb lub łączenie dwóch łańcuchów. Nie ma specyficznego zachowania dla tablic, więc konwertuje je na łańcuchy, a następnie je łączy.

Jeśli chcesz połączyć dwie tablice, aby utworzyć nową, użyj .concat metody :

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

Jeśli chcesz efektywnie dodawać wszystkie elementy z jednej tablicy do drugiej, musisz użyć the .metoda 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 + operator jest zdefiniowany w sekcji ECMA-262 5e 11.6.1:

11.6.1 operator dodawania ( + )

Operator dodawania wykonuje konkatenację łańcuchową lub dodawanie liczbowe. Produkcja AdditiveExpression : AdditiveExpression + MultiplicativeExpression jest oceniana w następujący sposób:

  1. niech lref będzie wynikiem oceny AdditiveExpression.
  2. niech lval będzie GetValue(lref).
  3. niech {[10] } będzie wynikiem oceny MultiplicativeExpression.
  4. niech rval będzie GetValue(rref).
  5. niech lprim będzie ToPrimitive(lval).
  6. niech rprim będzie ToPrimitive(rval).
  7. If Type(lprim) is String or Type(rprim) is String, then
    1. zwraca łańcuch będący wynikiem połączenia ToString(lprim), po którym następuje ToString(rprim)
  8. zwraca wynik zastosowania operacji dodawania do ToNumber(lprim) i ToNumber(rprim). Zob. Uwaga poniżej 11.6.3.

Widać, że każdy operand jest konwertowany ToPrimitive. Czytając dalej możemy stwierdzić, że ToPrimitive będzie zawsze konwertować tablice na ciągi znaków, uzyskanie tego wyniku.

 242
Author: Jeremy Banks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-15 08:55:23

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

Reprezentacja łańcuchowa dla pierwszej tablicy będzie "1,2" a drugi byłby "3,4". Tak więc po znalezieniu znaku +, nie może on sumować tablic, a następnie łączyć ich jako ciągi znaków.

 43
Author: Doug,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-19 17:09:30

+ łączy łańcuchy, więc konwertuje tablice na łańcuchy.

[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]
 39
Author: Rocket Hazmat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-19 16:58:50

W JavaScript operator dodawania binarnego (+) wykonuje zarówno dodawanie liczbowe, jak i konkatenację łańcuchów. Jeśli jednak pierwszy argument nie jest ani liczbą, ani łańcuchem, to przekształca go w łańcuch (stąd "1,2"), to robi to samo z drugim "3,4" i łączy je z "1,23,4".

Spróbuj użyć zamiast tego metody" concat " tablic:

var a = [1, 2];
var b = [3, 4];
a.concat(b) ; // => [1, 2, 3, 4];
 21
Author: maerics,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-19 17:00:30

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

 19
Author: tadman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-19 16:57:29

Wygląda na to, że JavaScript zamienia twoje 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
Author: Adam Fabicki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-19 16:57:28

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

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

I tak, aby rozwiązać problem, najlepiej byłoby dodać dwie tablice w miejscu lub bez tworzenia nowej tablicy:

var a=[1,2];
var b=[3,4];
a.push.apply(a, b);
 14
Author: user286806,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-27 01:58:42

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

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

 12
Author: Jamie Dixon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-19 16:57:03

Byłoby miło, gdybyś mógł przeciążać operatory w JavaScript, ale nie możesz: Czy Mogę zdefiniować własne przeciążenia operatorów w Javascript? możesz zhakować tylko operator"==", który konwertuje na ciągi przed porównaniem: http://blogger.xs4all.nl/peterned/archive/2009/04/01/462517.aspx

 8
Author: George Birbilis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:02

Jest tak dlatego, że operator + zakłada, że operatory są łańcuchami, jeśli nie są liczbami. Tak więc najpierw konwertuje je na ciąg i konkatedry, aby dać końcowy wynik, jeśli nie jest liczbą. Ponadto nie obsługuje tablic.

 8
Author: Prashant Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-20 11:06:17

Kolejny wynik przy użyciu zwykłego znaku " + " będzie następujący:

[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 to przekonwertuje zmienną a Z Tablicy na ciąg znaków! Pamiętaj o tym.

 0
Author: Blackhead,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-12 09:07:48

Niektóre odpowiedzi wyjaśniły, jak dzieje się nieoczekiwane niepożądane wyjście ('1,23,4'), a niektóre wyjaśniły, jak uzyskać to, co zakładają, że jest oczekiwanym pożądanym wyjściem ([1,2,3,4]), tj. konkatenację tablicy. Jednak charakter oczekiwanego pożądanego wyniku jest w rzeczywistości nieco niejednoznaczny, ponieważ pierwotne pytanie stwierdza po prostu " chciałem dodać elementy tablicy do innej...". Że może oznaczać konkatenację tablicy, ale może również oznaczać dodawanie krotki (np. tutaj i tutaj), tj. dodawanie wartości skalarnych elementów w jednej tablicy do wartości skalarnych odpowiadających im elementów w drugiej, np. łączenie [1,2] i [3,4] w celu uzyskania [4,6].

Zakładając, że obie tablice mają tę samą arytmetykę / 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]
 0
Author: Andrew Willems,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:07