Почему '{} == null' дает ошибку SyntaxError?

Я могу сравнить {} с истинным или ложным или с самим собой, но сравнение с нулевым или неопределенным дает синтаксическую ошибку. Это потому, что {} является значением объекта, а не ссылкой? Кажется странным, что это будет синтаксическая ошибка вместо какой-либо ошибки типа времени выполнения или просто сработает.

Чтобы прояснить, мне любопытно, почему это SyntaxError, в основном по сравнению с выполнением {} == {} которое не только не SyntaxError, но вообще не является ошибкой.

Example of weird behavior

Ответы

Ответ 1

При синтаксическом анализе кода существует два основных контекста: контекст выражения и контекст оператора. Например, тело функции является контекстом оператора, правая часть присваивания является контекстом выражения. Различать оба имеет смысл запрещать такие вещи, как:

 if( if(true) ) alert("nonsense");

Теперь у REPL действительно сложная задача: с одной стороны, они должны анализировать введенные функции и кодовые блоки, а с другой стороны, иногда вы просто хотите проверить, как выглядит определенный объект. Поэтому это:

 { a: 1, b: 2 }

на самом деле это ошибка SyntaxError в JavaScript, так как { в контексте оператора запускает блок кода, а затем : недопустим. Однако REPL достаточно умен и помещает этот объект в контекст выражения и оценивает его так, как если бы он был в скобках:

({ a: 1, b: 2 })

то же самое происходит для:

 {} == {}

который на самом деле также является SyntaxError, однако REPL также перемещает его в контекст выражения:

 ({} == {})

Это "перемещение в контекст выражения" является сложной задачей, и кажется, что REPL просто не видит здесь выражения:

 {} == null

и поэтому анализирует {} как блок. Это так, потому что REPL просто наивно проверяет, являются ли первый и последний символ { и }, что имеет место для {} == {} но не для {} == null.

Соответствующая часть исходного кода хрома:

 if (/^\s*\{/.test(text) && /\}\s*$/.test(text))
  text = '(' + text + ')';

executionContext.evaluate(text, "console", !!useCommandLineAPI, false, false, true, printResult);