Skip to content

Instantly share code, notes, and snippets.

@dSalieri
Last active January 31, 2022 23:06
Show Gist options
  • Save dSalieri/c38418370eddd5d2002018cc1263d382 to your computer and use it in GitHub Desktop.
Save dSalieri/c38418370eddd5d2002018cc1263d382 to your computer and use it in GitHub Desktop.
Сравнение операторов || и ??; как выглядит это внутри

Как выглядит это внутри:

Оператор ||:

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

Пока на этом все, надеюсь было интересно :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment