Почему `` (foo) = "bar" 'закончен в JavaScript? - программирование
Подтвердить что ты не робот

Почему `` (foo) = "bar" 'закончен в JavaScript?

В Node.js REPL (также тестируется в SpiderMonkey) последовательность

var foo = null;
(foo) = "bar";

с foo, впоследствии равным "bar", в отличие от null.

Это кажется противоречивым, потому что можно было бы подумать, что скобки по крайней мере разыгрывают bar и бросают недопустимую левую сторону в присваивании`.

Понятно, что когда вы делаете что-нибудь интересное, это не уступает вышеупомянутому пути.

(foo, bar) = 4
(true ? bar : foo) = 4

В соответствии с ECMA-262 на LeftHandExpressions (насколько я могу интерпретировать) нет действительных нетерминалов, которые приведут к заключению в скобки принимаются.

Есть ли что-то, чего я не вижу?

4b9b3361

Ответ 1

Это действительно так. В круглых скобках разрешено завернуть любую цель назначения.

Левая часть операции = - это LeftHandSideExpression, как вы правильно определили. Это можно отследить через различные уровни достоверности (NewExpression, MemberExpression) до PrimaryExpression, который, в свою очередь, может быть Cover­Parenthesized­Expression­And­Arrow­Parameter­List:

( Expression[In, ?Yield])

(на самом деле, когда анализируется с целью PrimaryExpression, он ParenthesizedExpression).

Итак, это действительно по грамматике, по крайней мере. Действительно ли это действительный синтаксис JS определяется другим фактором: ранняя статическая семантика ошибки. В основном это прозаические или алгоритмические правила, которые в некоторых случаях делают некоторые производственные расширения недействительными (синтаксические ошибки). Это, например, позволило авторам повторно использовать алгоритмы инициализации массива и объекта для деструктурирования, но только с применением определенных правил. В ранних ошибках для выражений присваивания мы находим

Это ранний Reference Error, если LeftHandSideExpression не является ни ObjectLiteral, ни ArrayLiteral, а IsValidSimpleAssignmentTarget для LeftHandSideExpression false.

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

Итак, что делает IsValidSimpleAssignmentTarget для LeftHandSideExpressions? В основном это позволяет присваивать доступ к свойствам и запрещает присваивания вызовам выражений. В нем ничего не говорится о простых первичных выражениях, которые имеют собственное правило IsValidSimpleAssignmentTarget. Все, что он делает, это извлечь выражение между круглыми скобками через Covered & shy; Parenthesized & shy; Expression operation, а затем снова проверить IsValidSimpleAssignmentTarget. Короче: (…) = … действителен, когда … = … действителен. Он даст true только для Identifiers (как в вашем примере) и свойств.

Ответ 2

В соответствии с предложением @dlatikay, следуя существующей догадке, исследование CoveredParenthesizedExpression дал лучшее понимание того, что происходит здесь.

По-видимому, причина, по которой не терминал не может быть найден в spec, чтобы объяснить, почему (foo) является приемлемым как LeftHandExpression, на удивление прост. Я предполагаю, что вы понимаете, как работают парсеры, и что они работают в двух отдельных этапах: Лексинг и Разбор.

То, что я узнал из этого небольшого исследования касательной, состоит в том, что конструкцию (foo) технически не доставляют парсеру, и поэтому двигатель, как вы думаете.

Рассмотрим следующее

var foo = (((bar)));

Как мы все знаем, что-то подобное совершенно законно. Зачем? Ну, вы визуально можете просто игнорировать скобки, в то время как утверждение остается в идеальном смысле.

Аналогичным образом, вот еще один верный пример, даже с точки зрения человеческой читаемости, поскольку в круглых скобках объясняется, что PEMDAS уже делает неявным.

(3 + ((4 * 5) / 2)) === 3 + 4 * 5 / 2
>> true

Одно из ключевых наблюдений может быть легко получено из этого, учитывая понимание того, как уже работают парсеры. (помните, что Javascript все еще разбирается (читать: скомпилирован), а затем запускается). В прямом смысле эти круглые скобки "указывают на очевидные".

Итак, все, что сказано, что именно происходит?

В принципе, круглые скобки (за исключением функциональных параметров) сворачиваются в правильные группировки их содержащих символов. IANAL, но в условиях неспециалиста это означает, что круглые скобки интерпретируются только для того, чтобы направлять парсер как группировать то, что он читает. Если контекст круглых скобок уже "по порядку" и, следовательно, не требует никакой настройки испущенного AST, тогда (машина) код испускается, как если бы эти скобки вообще не существовали.

Парсер более или менее ленив, полагая, что парнеры дерзкие. (что в этом краевом случае неверно)

Хорошо, и где именно это происходит?

Согласно 12.2.1.5 Статическая семантика: IsValidSimpleAssignmentTarget в спецификации,

Первичное выражение: (CoverParenthesizedExpressionAndArrowParameterList)

  • Пусть expr будет CoveredParenthesizedExpression of CoverParenthesizedExpressionAndArrowParameterList.
  • Возвращает IsValidSimpleAssignmentTarget выражения.

т.е. Если ожидать primaryExpression вернуть все, что находится внутри скобки, и использовать это.

Из-за этого в этом случае он не конвертирует (foo) в CoveredParenthesizedExpression{ inner: "foo" }, он преобразует его просто в foo, который сохраняет тот факт, что он является Identifier и, следовательно, синтаксически не обязательно лексически, действительный.

TL; DR

Он просмотрел.

Хотите немного больше понимания?

Отметьте ответ @Bergi.