Почему {} + {} больше не NaN в консоли Chrome?

144

Сегодня я заметил, что Chrome 49 больше не выводит NaNпри вводе {}+{}в консоли. Вместо этого он выводит строку [object Object][object Object].

Почему это? Язык изменился?

Филип Хаглунд
источник
13
Похоже, что Chrome теперь обрабатывает эту операцию как конкат строки, а не добавление. ПОЧЕМУ это, я не знаю, поэтому это комментарий, а не ответ :) попробуйте, var e = {}; e.toString()и вы поймете, что я имею в виду
user428517
19
"Язык изменился?" Нет.
Феликс Клинг
6
@FelixKling Изменится ли язык? нет ... нет. : c
кот
18
Может быть, WATMAN как-то связан с этим?
Рикстер
1
@rickster вот как я это нашел. Я воссоздал это для презентации.
Филип Хаглунд

Ответы:

152

Chrome devtools теперь автоматически оборачивает все, что начинается {и заканчивается }в неявной паре скобок ( см. Код ), чтобы заставить его вычислять как выражение. Таким образом, сейчас {}создается пустой объект. Это можно увидеть, если вернуться к истории ( ), в которой будет содержаться предыдущая строка (…).

Зачем? Я не знаю, но я мог бы предположить, что это уменьшает путаницу для новичков, которые не знают о блоке vs-object-literal, и это также более полезно, если вы просто хотите оценить выражение.

И на самом деле это рассуждение, как обсуждалось в баге 499864 . Чистое удобство. И потому что узел REPL имел это также ( см. Код ).

Берги
источник
182
Глупый Chrome, {a:1}),({b:2}должен выдавать ошибку, а не выдавать объект.
Oriol
29
Вот что происходит, когда вы анализируете произвольно глубокие вложенные структуры с помощью регулярного выражения stackoverflow.com/questions/1732348/…
Филип Хаглунд
4
Я понятия не имею, почему, но почему-то, когда я вижу там свои сообщения, я чувствую себя «знаменитым», хотя эта страница так же общедоступна, как и эта: D Странная проблема StackOverflow. Вот мой старый ответ о проблеме stackoverflow.com/questions/17268468/…
Бенджамин Грюнбаум
3
Мне не нравится текущая реализация и я планирую это исправить. bugs.chromium.org/p/chromium/issues/detail?id=499864#c17
Зирак,
1
@ Zirak Удачи в исправлении этого мусора, IMO, его нужно как можно скорее отбросить. Но если вы хотите улучшить его, подумайте о добавлении новой строки перед вставкой, )если она есть в комментарии, например, {a:3} // :-}все еще может появиться объект.
Oriol
44

Если вы нажмете стрелку вверх после проверки этого, вы заметите, что вместо {} + {}этого отображается ({} + {}), что приводит к "[object Object][object Object]".

Для сравнения, в Firefox по- {} + {}прежнему отображается NaN, но если вы делаете ({} + {})это, также отображается "[object Object][object Object]".

Итак, похоже, что Chrome автоматически добавляет окружающие скобки, когда видит эту операцию.

Дж. Титус
источник
22
этот ответ правильный. но вау, чувак, я не уверен, что мне нравится, что хром делает это. плохой гугл.
user428517
1
@sgroves Мне было бы интересно узнать, то же самое на Канарских островах, и было ли это сделано специально или это ошибка.
Дж. Титус
8
{} + {}когда не "очищено", ({} + {})обрабатывается как, + {}потому что {}анализируется как пустой блок.
Григорий Нисбет,
7
Почему бы это вернуть NaN в первую очередь?
0x499602D2
25
@ 0x499602D2: Потому что, если вы не сделаете парены (или иным образом не заставите парсер перейти к ожиданию выражения, а не оператора), инициал {}будет просто пустым блоком кода и будет игнорироваться, оставляя нас с +{}, который является унарным +и пустым объектом инициализатор. +будет принуждать свой аргумент на номер, который включает в себя преобразование объекта в примитив (который будет в конечном итоге быть toStringв этом случае, в результате "[object Object]"), и таким образом мы получаем +"[object Object]"что , NaNпотому что "[object Object]"не может быть преобразовано в действительное число.
TJ Crowder
4

Начиная с Chrome 54 относительно консоли:

I- «Я преобразовал этот блок в объект для вас» -Клипы К сожалению, я добавил цитату Clippy самостоятельно. Консоль не дает никакой информации о том, что она для вас сделала.

Новые правила невероятно просты, избавляя нас от необходимости кропотливо набирать эти 2 сложные символы o=или 0,перед вставкой литералов объектов в консоль:

  • Если у вас есть код, который начинается с: необязательный пробел, (комментарии не допускаются), за которым следует a {;
  • и этот код может быть интерпретирован как объект;
  • и этот объект не сопровождается никаким другим кодом, если:
  • код после первого объекта является бинарным оператором,
  • тогда может быть сколько угодно операций, включая группировки
  • при условии, что последний оператор имеет литерал Object в правой позиции;
  • и этот последний объект не был сгруппирован в парены
  • и этот код не заканчивается точкой с запятой
  • и после кода нет комментариев (внутренние комментарии разрешены, если они не находятся в начальной или конечной позиции)
  • тогда и только тогда ваш JavaScript (который может быть, а может и не быть действительным кодом) будет повторно интерпретирован как действительный объект. Вы не будете проинформированы о том, что ваш код был переосмыслен.

{wat:1}),({wat:2} Наконец-то снова ошибка.

{let i=0;var increment=_=>i++} наконец, правильно разрешено, что является довольно хорошим способом сделать замыкания.

Тем не менее, следующее - неправильно объект, это как удобство, как упомянуто @Bergi, он неправильно интерпретирует JS, чтобы помочь вам! Спецификация говорит, что это блок с помеченным оператором "foo" с литералом 1, который никому не назначен.

{foo:1}

Выше должно быть так же, как

if(1) {
    foo: 1
}

Следующее корректно обрабатывается как блок ... потому что перед ним есть комментарий!

//magic comment
{foo:1}

Так что это:

{foo:1}
//also magic

Это объект:

{foo:
//not so magic comment
1}

Это ошибка

//not so magic comment
{foo:1}.foo

Так что это:

{foo:1}.foo

Это отлично:

1..wat

undefined

так это

['foo'][0]

Следующий корректно интерпретируется как объект, помещенный в позицию выражения с помощью a, 0,что, как правило, позволяет нам однозначно убедиться, что у нас есть выражение вместо оператора.

0,{foo:1}.foo

Я не понимаю, почему они оборачивают ценность в паранах. У JS есть несколько нелепых дизайнерских решений, но пытаться заставить его вести себя лучше в этой ситуации, на самом деле не вариант, консоль должна правильно запускать JS, и мы должны быть уверены, что Chrome не просто догадывается, что он думает, что мы действительно хотел сделать что-то еще.

Если вам не нравятся запятые операторы, вы можете использовать присваивание

x = {foo:1}.foo

Потому что так оно и есть

{} + {} + {}

"[object Object][object Object][object Object]"

;{} + {} + {}

"NaN[object Object]"

Сумасшедшим и последовательным я могу справиться ... сумасшедшим и непоследовательным, нет, спасибо!

Джеймс Уэйкфилд
источник
REPL - это не язык, а REPL. Он передает строки на язык среди других вещей . Вот несколько вещей, которые Chrome REPL делает с самим языком . Они очень полезны, поэтому я очень рад, что они не придерживались только простого языка.
Ган
@gman REPL Считывает строку, оценивает ее, печатает результаты и затем готовится прочитать следующий фрагмент динамического кода. Ничто на связанной странице не было недопустимым JavaScript. Переменная «$ _», ограниченная контекстом консоли, - это удобство, которое имеет смысл только в REPL. Тем не менее «$ _» является допустимым именем переменной, остальные являются обычными функциями и классами, вызываемыми с помощью обычного JavaScript.
Джеймс Уэйкфилд
Не уверен, какова ваша точка зрения. Я хочу сказать, что язык - это одно, а среда, в которой он работает, - это другое. Вы привели пример в своем ответе. В JS {foo:1}и {foo:1}//производят тоже самое. В Chrome JS REPL их нет. REPL делает больше, чем просто оценивает JS. Он обрабатывает строки и решает разные вещи.
GMan
var x = eval('{a:1}')В действительном JavaScript х теперь равен 1, а не более интуитивному объекту {a: 1}. Да, это странно, но вы не можете просто сменить язык, потому что он делает странные вещи. Все, кроме строк JSON, интерпретируется как JavaScript и оценивается. Печатать 0,перед вставкой JSON не сложно, в противном случае я был бы рад предупреждению о том, что строка была интерпретирована как объект вместо JavaScript для удобства.
Джеймс Уэйкфилд