Как выглядит это внутри:
Оператор ||:
LogicalORExpression : LogicalORExpression || LogicalANDExpression
1. Let lref be the result of evaluating LogicalORExpression. 2. Let lval be ? GetValue(lref). 3. Let lbool be ! ToBoolean(lval). 4. If lbool is true, return lval. 5. Let rref be the result of evaluating LogicalANDExpression. 6. Return ? GetValue(rref).Пояснение: Видим что во втором шаге мы получаем значение первого операнда, а уже в третьем преобразуем в логическое значение. Четвертый шаг проверяет что явилось результатом преобразования и если
true
вернуть значение операнда до преобразования. В противном случае получить значение второго операнда и вернуть значение (преобразование в логическое значение не требуется)
Оператор ??:
CoalesceExpression : CoalesceExpressionHead ?? BitwiseORExpression
1. Let lref be the result of evaluating CoalesceExpressionHead. 2. Let lval be ? GetValue(lref). 3. If lval is undefined or null, then a. Let rref be the result of evaluating BitwiseORExpression. b. Return ? GetValue(rref). 4. Otherwise, return lval.
Пояснение: Второй шаг получает из левого операнда значение. Третий шаг проверяет а равен ли значению undefined
или null
левый операнд и если да, тогда вернуть полученное значение из правого операнда. Четвертый шаг вернуть значение левого операнда (конечно этот шаг достижим если третий шаг провалил проверку на undefined
или null
)
Вот так все просто выглядит внутри.
Кстати полифиллом в виде функции будет следующий пример (используется нестрогая проверка на null
, так как null
и undefined
равны друг другу):
function coalescence(lval, rval){
return (lval == null) ? rval : lval
}
coalescence(null, 1); /// тоже что и null ?? 1
coalescence(undefined, 2); /// тоже что и undefined ?? 2
coalescence(10, 3); /// тоже что и 10 ?? 3
Почему выражение 1 ?? 2 && 3
вызывает ошибку, а 1 ?? 2 & 3
или 1 ?? (2 && 3)
нет?
Архитекторы языка посчитали чтобы избавить себя и разработчиков от путаницы приоритетов с операторами ||
и &&
, нужно исключить оператор ??
из ветки приоритетов логических операторов. Поэтому в спецификации можно увидеть как производство ??
просто пропускает цепочку с ||
и &&
, что в конечном итоге приводит к ошибке синтаксиса. Поэтому выражение 1 ?? 2 && 3
на этапе анализа правого выражения 2 && 3
ловит ошибку так как не может разбить это производство в комбинации с ??
. Скобочное выражение 1 ?? (2 && 3)
работает потому как скобочное производство находится уровнями ниже и соответственно не попадает в зону аннулированного синтаксиса. Что касается 1 ?? 2 & 3
, так тут все просто, это корректный синтаксис и в приоритезации он идет следом после после группы &&
и ||
.
Теперь давайте я сопоставлю производства с нашими выражениями и укажу где синтаксис ломается а где идет дальше:
1) Как выглядят базовые выражения:
CoalesceExpression: CoalesceExpressionHead ?? BitwiseORExpression
1 ?? 2
LogicalANDExpression: LogicalANDExpression && BitwiseORExpression
2 && 3
2) Как выглядят комплексные выражения:
CoalesceExpression: CoalesceExpressionHead ?? BitwiseORExpression
1 ?? 2 && 3
/// Uncaught SyntaxError: Unexpected token '&&', так как BitwiseORExpression не содержит LogicalANDExpression, и поэтому ошибка.
CoalesceExpression: CoalesceExpressionHead ?? BitwiseORExpression
1 ?? (2 && 3)
/// что в свою очередь преобразовывается в (стек-трейс преобразований)
CoalesceExpression: CoalesceExpressionHead ?? BitwiseXORExpression
CoalesceExpression: CoalesceExpressionHead ?? BitwiseANDExpression
CoalesceExpression: CoalesceExpressionHead ?? EqualityExpression
CoalesceExpression: CoalesceExpressionHead ?? RelationalExpression
CoalesceExpression: CoalesceExpressionHead ?? ShiftExpression
CoalesceExpression: CoalesceExpressionHead ?? AdditiveExpression
CoalesceExpression: CoalesceExpressionHead ?? MultiplicativeExpression
CoalesceExpression: CoalesceExpressionHead ?? ExponentiationExpression
CoalesceExpression: CoalesceExpressionHead ?? UnaryExpression
CoalesceExpression: CoalesceExpressionHead ?? UpdateExpression
CoalesceExpression: CoalesceExpressionHead ?? LeftHandSideExpression
CoalesceExpression: CoalesceExpressionHead ?? NewExpression
CoalesceExpression: CoalesceExpressionHead ?? MemberExpression
CoalesceExpression: CoalesceExpressionHead ?? PrimaryExpression
CoalesceExpression: CoalesceExpressionHead ?? CoverParenthesizedExpressionAndArrowParameterList
CoalesceExpression: CoalesceExpressionHead ?? (Expression)
CoalesceExpression: CoalesceExpressionHead ?? (LogicalANDExpression)
CoalesceExpression: CoalesceExpressionHead ?? (LogicalANDExpression && BitwiseORExpression)
CoalesceExpression: CoalesceExpressionHead ?? BitwiseORExpression
1 ?? 2 & 3
/// что в свою очередь преобразовывается в (стек-трейс преобразований)
CoalesceExpression: CoalesceExpressionHead ?? BitwiseXORExpression
CoalesceExpression: CoalesceExpressionHead ?? BitwiseANDExpression
CoalesceExpression: CoalesceExpressionHead ?? BitwiseANDExpression & EqualityExpression
Пока на этом все, надеюсь было интересно :)