Каков результат добавления объекта и массива в JavaScript? - PullRequest
5 голосов
/ 23 января 2011

Я пробовал этот код в адресной строке:

javascript: alert({} + [])

Результат: [объект Объект].

javascript: alert(typeof ({} + []))

Результат: строка.

Может кто-нибудь объяснить мне, что происходит?

Ответы [ 5 ]

4 голосов
/ 23 января 2011

Оператор конкатенации (+) объединяет два строковых значения вместе.Если вы даете ему вещи, которые не являются строковыми значениями, то он сначала вызывает для них метод .toString().

В ответ на комментарий ниже: «Да, это так!»

Object.prototype.toString = function () { return "a"; };
Array.prototype.toString = function () { return "b"; };
var foo = {} + [];
alert(foo); // alerts 'ab'

Без вышеуказанных модификаций прототипов, если у вас есть alert({} + []), тогда вы берете {}.toString() (что составляет "[Object object]") и [].toString() (то есть "", поскольку массив пуст), затем объединяете их (который все еще "[Object object]").Это строка, и typeof скажет вам, что это строка.

1 голос
/ 29 июня 2016

Боюсь, это немного, но сложнее, чем объясняется здесь.

Название вопроса:

Каков результат добавления объекта и массива в JavaScript?

И тогда возникает вопрос о выражении {}+[], которое каждый здесь предполагает, что оно оценивается как '[object Object]' - , но всегда ли это?

Нажмите Shift + Control + J прямо сейчас и введите {}+[] в приглашении >:

enter image description here

Может быть, это ошибка браузера? Давайте попробуем то же самое в Node:

enter image description here

Здесь происходит что-то интересное.

Плюс (+) - который на самом деле называется «оператор сложения» , а не «оператор конкатенации» , как кто-то здесь написал - см. ECMA- 262, 6-е издание, раздел 12.7.3 - Оператор сложения (+) - выполняет объединение строк или числовое сложение , что очень важно для понимания подобных примеров.

Кто-то однажды задал мне такой вопрос:

Если alert({}+[]) показывает '[object Object]', а x = {}+[] помещает '[объект объекта]' в x, тогда почему запись {}+[] в консоли или узле REPL дает 0?

enter image description here

Ответ заключается в том, что при использовании оператора «плюс» для объекта и массива они покрывают их строками - строкой '[object Object]' и пустой строкой соответственно - здесь мы на самом деле не добавляем объект в объект массив! {} интерпретируется как пустой блок и вычисляется как ничто, поэтому + теперь оценивается как унарный оператор , приводящий массив [] к числу, которое оказывается нулевым для пустой массив - но это не количество элементов, а 0 для пустого массива, первый элемент преобразуется в число, если это может быть, или NaN, если это невозможно, для одноэлементных массивов, и NaN для любых массивов с более одного элемента.

Еще несколько интересных результатов, попробуйте все комбинации {} и [] с операторами +, -, * и /:

$ node
> []+[]
''
> {}+{}
'[object Object][object Object]'
> []+{}
'[object Object]'
> {}+[]
0
> []-[]
0
> {}-{}
NaN
> []-{}
NaN
> {}-[]
-0
> []*[]
0
> {}*{}
NaN
> []*{}
NaN
> {}*[]
... ^C
> []/[]
NaN
> {}/{}
NaN
> []/{}
NaN
> {}/[]
SyntaxError: Invalid regular expression: missing /
    at Object.exports.createScript (vm.js:24:10)
    at REPLServer.defaultEval (repl.js:137:25)
    at bound (domain.js:250:14)
    at REPLServer.runBound [as eval] (domain.js:263:12)
    at REPLServer.<anonymous> (repl.js:392:12)
    at emitOne (events.js:82:20)
    at REPLServer.emit (events.js:169:7)
    at REPLServer.Interface._onLine (readline.js:210:10)
    at REPLServer.Interface._line (readline.js:546:8)
    at REPLServer.Interface._ttyWrite (readline.js:823:14)

Это один из лучших способов выучить все причуды языков наизнанку.

1 голос
/ 23 января 2011

Это немного сложнее.

Вы найдете очень хорошее объяснение, как это работает здесь: http://www.adequatelygood.com/2010/3/Object-to-Primitive-Conversions-in-JavaScript

Но, похоже, изменился описанный Бен Черри (и то, что я обдумал). Если вы запустите его пример:

function population(country, pop) {
    return {
        country: country,
        pop: pop,

        toString: function () {
            return "[Population " + 
                "\"" + country + "\" " +
                pop +
            "]";
        },

        valueOf: function () {
            return pop;
        }
    };
}

var america_pop = population("USA", 350e6);
var mexico_pop = population("Mexico", 200e6);
var canada_pop = population("Canada", 200e6);

alert(america_pop); // [Population "USA" 350000000

var north_america_pop = america_pop + mexico_pop + canada_pop;

alert(north_america_pop); // 750000000

Это больше не так, оповещения будут:
350000000
750000000

alert (obj), вызов valueOf () больше не toString (), исполняется, если вы используете Array.join

alert([america_pop]); // [Population "USA" 350000000

Уже был поток о: valueOf () и toString () в Javascript

Они поясняют, что valueOf всегда вызывается, когда [подсказка] является числом, и это всегда так, кроме случаев, когда вы присоединяетесь к массиву. это сбивает с толку, потому что если вы вызываете 'string' + 'string', это определенно является строковым контекстом, но JS сначала рассмотрит числовой контекст и всегда вызывает метод valueOf (), а не toString (), если это примитивное значение 1020 *

1 голос
/ 23 января 2011

Похоже, что оператор + не определен, чтобы принимать аргументы как один [] и один {}, он в основном преобразует оба в строки (имеет больше смысла, чем попытка привести их в числа), а затем применяет + как оператор конкатенации.

Edit: В ответ на измененный вопрос, я думаю, они все еще сначала конвертируются в строку. Вот сеанс в spidermonkey, где я его опробовал:

js> x=[]+{}
[object Object]
js> z=x[0]
[
js> x.length
15
js> x=[]+{}
[object Object]
js> x.length
15
js> x[0]
[
js> x[1]
o
js> for (var i=0;i<x.length;i++) {print(x[i]);}
[
o
b
j
e
c
t

O
b
j
e
c
t
]
js> typeof(x)
string
js> print(x)
[object Object]

В результате {}+[] является строкой, но не пустой строкой. Скорее это строка "[объект объекта]".

0 голосов
/ 23 января 2011

В основном будет вызван метод toString. Вы можете переопределить поведение по умолчанию, написав метод toString, который возвращает число.

var obj1 = {
        toString: function () {
            return 1;
        }
    },
    obj2 = {
        toString: function () {
            return 2;
        }
};
alert(typeof (obj1 + obj2));
...