Подтвердить что ты не робот

Почему логические операторы в JavaScript остаются ассоциативными?

логические операторы AND и OR являются единственными ленивыми операторами в JavaScript вместе с тройной условный оператор. Они протестированы для в соответствии с логическими операторами MDN в JavaScript остаются ассоциативными. Это счетчик интуитивно понятен. По моему скромному мнению, они должны быть правильными ассоциативными. Хаскелл поступает правильно. Логические операторы в Haskell являются правильными ассоциативными:

infixr 3 &&
infixr 2 ||

Рассмотрим следующее выражение в Haskell:

False && True && True && True

Поскольку && является правильным ассоциативным в Haskell, указанное выше выражение эквивалентно:

False && (True && (True && True))

Следовательно, не имеет значения, что оценивает выражение (True && (True && True)). Из-за первого False все выражение сводится к False за один шаг.

Теперь рассмотрим, что произойдет, если && оставлено ассоциативным. Выражение будет эквивалентно:

((False && True) && True) && True

Теперь было бы 3 сокращения для оценки всего выражения:

((False && True) && True) && True
(False && True) && True
False && True
False

Как вы можете видеть, логические операторы имеют смысл быть правильной ассоциативной. Это подводит меня к моему фактическому вопросу:

Почему логические операторы в JavaScript оставлены ассоциативными? Что спецификация ECMAScript должна сказать об этом? Являются ли логические операторы в JavaScript фактически правильными ассоциативными? Имеются ли в документах MDN некорректная информация об ассоциативности логических операторов?


Изменить: В соответствии с спецификация логические операторы остаются ассоциативными:

LogicalANDExpression = BitwiseORExpression
                     | LogicalANDExpression && BitwiseORExpression

LogicalORExpression = LogicalANDExpression
                    | LogicalORExpression || LogicalANDExpression
4b9b3361

Ответ 1

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

Во всех языках семейства C, о которых я знаю (к которым принадлежит Javascript), логические операторы остаются ассоциативными. Итак, возникает реальный вопрос, почему C-подобные языки определяют логические операторы как лево-ассоциативные? Поскольку выбранная ассоциативность не имеет значения (с точки зрения семантики и с точки зрения эффективности), мое подозрение заключается в том, что была выбрана наиболее "естественная" (как в "то, что большинство других операторов" ) ассоциативность, У меня есть какие-то источники для поддержки моих требований. Другое возможное объяснение состоит в том, что левые ассоциативные операторы занимают меньше пространства стека для синтаксического анализа с использованием анализатора LALR (что в настоящее время не является большой проблемой, но, вероятно, вернулось, когда появился C).

Ответ 2

Рассмотрим этот код:

console.log(   true || (false && true) );   // right associative (implicit)
console.log(  (true || false) && true  );   // left associative (Javascript)

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

Итак, теперь рассмотрим это:

    var name = "";

    // ----------------------------------------
    // Right associative
    // ----------------------------------------
    name = "albert einstein";
    console.log("RIGHT : %s : %s", true || (false && updateName()), name);

    // ----------------------------------------
    // Left Associative
    // ----------------------------------------
    name = "albert einstein";
    console.log("LEFT  : %s : %s", (true || false) && updateName(), name);

    function updateName() {
        name = "charles manson";
        return true;
    }

Вывод:

    RIGHT : true : albert einstein
    LEFT  : true : charles manson

Оба выражения возвращают true, но только левая связанная версия должна была вызвать updateName(), чтобы вернуть ответ. Соответствующая версия отличается. Он оценивает только первый аргумент в (false && updateName()), потому что второй аргумент не может изменить false на true.

Помните эти две точки:

  • Приоритет оператора описывает порядок вложенности составных выражений типов разных.
  • Ассоциативность операторов описывает порядок вложенности составных выражений с приоритетом оператора same.

Обратите внимание, что ни одна из двух точек выше не меняет способ интерпретации отдельного выражения, а интерпретируются только выражения составные. Ассоциативность происходит на более высоком уровне.

Ассоциативность операторов, а также приоритет оператора имеют огромное влияние на поведение языка. Понимание того, что эти различия имеют решающее значение для возможности использования и быстрого понимания функциональных различий в различных языках программирования. Вы определенно получаете большие пальцы от меня для вашего вопроса, и я надеюсь, что это немного прояснит ситуацию. Будьте осторожны.

Ответ 3

Простой ответ: представьте var я = null; if (i == null || i.getSomeValue())... Если не оставаться ассоциативным, второй тест будет оцениваться сначала, давая вам исключение.