Ответ 1
При попытке сделать это:
var b1, b2;
b1 = !b2 = true;
document.write(b1, " ", b2);
Поскольку они функционально эквивалентны ‡ вы в основном делаете:
var b1, b2;
!b2 = true;
b1 = true; //just the value of b2, not b2 itself
document.write(b1, " ", b2);
В строке !b2 = true
вы пытаетесь назначить выражение, которое оценивает значение (слева), до значения - это совершенно не имеет смысла. Подумайте об этом так:
-
!b2
присваиваетсяtrue
.!b2
является выражением и оценивается как логическое значение, а не переменная. - Это будет аналогично выполнению
1 + 1 = 2
. Поскольку1 + 1
оценивается до значения, вы не можете назначить это значение2
, другое значение. Вы должны назначить значение переменной, поскольку присвоение значения к значению семантически и логически недействительно. - Еще один способ подумать об этом - осознать это:
1 + 1
- значение.2
- значение. Вы не можете присвоить значение значению, так как это значение уже имеет значение. Константа, такая как2
имеет значение2
, ее нельзя изменить. Что делать, если мы попробовали1 - 1 = 2
?0
, константа и значение не могут быть2
, потому что это константа.
Таким образом, семантически и логически неверно присваивать значение значению. Вы не можете назначить 0
2
так же, как вы не можете назначить false
true
.
Если вы хотите лучше понять синтаксис и семантику и почему это выбрасывает ReferenceError
, вы можете вникать в ECMAScript® 2015 Language Specification †. По спецификации:
Раздел 12.14.1 - Операторы присваивания - Статическая семантика: ранние ошибки
AssignmentExpression : LeftHandSideExpression = AssignmentExpression
- Это ранний Reference Ошибка, если
LeftHandSideExpression
не является ниObjectLiteral
, ниArrayLiteral
иIsValidSimpleAssignmentTarget
изLeftHandSideExpression
является ложным.
Где IsValidSimpleAssignmentTarget
:
Раздел 12.14.3 - Операторы присваивания - Статическая семантика: IsValidSimpleAssignmentTarget
AssignmentExpression : YieldExpression ArrowFunction LeftHandSideExpression = AssignmentExpression LeftHandSideExpression AssignmentOperator AssignmentExpression
1. Вернуть false.
Теперь оглянитесь на свой код: b1 = !b2 = true
. b1 = !b2
отлично, потому что это LeftHandSideExpression = AssignmentExpression
, поэтому возвращается значение true для IsValidSimpleAssignmentTarget
. Проблема возникает, когда мы проверяем !b2 = true
. Если мы посмотрим на определение LeftHandSideExpression
:
Раздел 12.3 - Левые выражения
Синтаксис
LeftHandSideExpression : NewExpression CallExpression
(Вы можете просмотреть определения NewExpression
и CallExpression
в ссылке выше)
Вы можете видеть, что !b2 = true
не является допустимым AssignmentExpression
, так как он не соответствует критериям LeftHandSideExpression = AssignmentExpression
. Это связано с тем, что !b2
не является допустимым LeftHandSideExpression
, также не ObjectLiteral
и ArrayLiteral
, поэтому IsValidSimpleAssignmentTarget
возвращает false, бросая ReferenceError
. Обратите внимание, что ошибка - это ранняя ошибка, то есть она бросается перед выполнением любого кода, как отмечено в @Bergi комментарий.
Вы можете бороться с этим, выполнив одно из следующих действий, в зависимости от вашего желаемого результата:
b1 = !(b2 = true);
С круглыми скобками внутри скобок имеет приоритет над внешним. Таким образом, b2
назначается, а так как он true
, внутри круглых скобок вычисляется true
. Затем это эквивалентно:
b1 = !(true);
Как и в круглых скобках, оценивается как true
, как указано выше. b1
будет считаться противоположным b2
, как и ожидалось, и b2
будет true
.
Если вы хотите, чтобы b1
был true
и b2
равным false
, выполните реструктуризацию оператора следующим образом:
b2 = !(b1 = true);
Таким образом, это полностью противоположно сказанному, давая b1 = true
и b2 = false
.
‡ Как отмечает @Bergi в комментариях, b1
присваивается правый операнд true
в этом случае, а не !b2
.
† Хотя большинство браузеров в настоящее время не поддерживают все функции ECMAScript 6 (2015) и вместо этого используют ECMAScript 5.1 (2011), спецификация для обеих версий одинакова. Все определения одинаковы, и поэтому объяснение остается в силе.