Страницы

Поиск по вопросам

пятница, 5 октября 2018 г.

{} + {}. Почему такой результат?

{} + {} "[object Object][object Object]"
В статье Преобразование объектов: toString и valueOf в разделе Итоги описывается поведение объекта( {} ) в основном потоке кода, но в консоли поведение отличается. Я даже где - то видел подобный пример: {} + {}. Там говорилось, что левый операнд считается как пустой "блок кода", а правый приводиться к числу, результатом который будет NaN
За одно хотел спросить, как видит парсер это пример: {} - {}
Парсер игнорирует левый объект и воспринимает его как "блок кода". Тогда возникает вопрос, почему в примере выше происходит конкатенация? Он их приводит к числу(NaN) и вычитает.

P.S: Знал бы английский и умел бы хорошо понимать документация ECMAScript, я бы не спрашивал.


Ответ

Основной поток кода - это место, которое не является частью выражения.
Вот моменты языка, которые могут быть размещены только в основном потоке кода:
function declaration (отличается от function expression) блок кода (отличается от объекта) метки (отличаются от имён свойств) все синтаксические конструкции языка: if, else, try, var и т. д.
Если есть две похожие конструкции, одна из которых может существовать только в основном потоке, то именно этот критерий будет использоваться для их различения: если код размещён в основном потоке кода, то выбирается соответствующая конструкция, а если в выражении, то другая.
Что касается записи {}+{}, то в случае основного потока кода её значение обычно вообще никуда не попадает, хотя и выводится в REPL-средах как результат. Первая фигурная скобка означает открытие блока кода, затем вторая его заканчивает. Потом попадается плюс - левого операнда у нас нет, значит он унарный. Мы уже находимся в выражении. Фигурная скобка в выражении начинает объект. Следующая - заканчивает объект. Получается +{}, затем +"[object Object]" и NaN.
В случае же с console.log сам вызов функции образует выражение. Поэтому первая пара скобок превращается в объект, а вся сумма после приведения типов в конкатенацию строк.
Единственный способ (по крайней мере в ES2018-) получить в коде это передать строку с кодом в eval.
function run(code) { try { console.log(eval(code)) } catch(e) { console.log(e.name + " " + e.message) } } run('{console.log("I am the code block")} + {i:0, am:1, an:2, object:3}') run('({a:0, pair:1} + {of:2, objects:3})') // круглые скобки run('{not_object:0} + {object:1}') // метка! run('{not_object:0, really_not:1} + {object:2}') // ошибка - метка не может быть вне основного потока run('{not_object:0; really_not:1} + {object:1}') // `;`, а не `,` - две метки
Что касается консоли хрома - судя по всему они сделали умное определение, является ли нечто в фигурных скобках объектом или куском кода. Причём, предпочтение отдаётся объекту. Думаю, это сделано для большего удобства, что если ты вводишь выражение в консоль, то ты хочешь результат выражения, который ты не получишь в основном потоке кода. Но стоит заметить, что эта штука в консоли работает только для top-level-кода (да и то не всегда), и не распространяется на вложенный код:

Комментариев нет:

Отправить комментарий