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

Почему объявление функции в блоке условий, предназначенное для работы в Chrome, но не в Firefox?

Почему следующие коды выдают разные результаты между Chrome и Firefox?

f = function() {return true;}; 
g = function() {return false;}; 
(function() { 
   if (g() && [] == ![]) { 
      f = function f() {return false;}; 
      function g() {return true;} 
   } 
})(); 
console.log(f());

В Chrome: результат false. Однако в Firefox это true.

Ключевая строка вышеуказанных кодов - строка 4, и основываясь на моем знании подъема имени функции, функция g должна быть в строке 6, а именно строка 2 переопределена линией 6. ИМО, поведение Chrome корректен.

Я прав? если да, то почему Firefox выводит разные результаты?

4b9b3361

Ответ 1

ECMAScript 5, текущая официальная спецификация языка JavaScript, не определяет поведение для деклараций функций внутри блоков.

Цитата Kangax:

ФункцияDeclarations разрешена только в Program или FunctionBody. Синтаксически они не могут отображаться в блоке ({ ... }) - например, в выражениях if, while или for. Это связано с тем, что Blocks может содержать только выражения, а не SourceElements, которые являются FunctionDeclaration. Если мы тщательно рассмотрим правила производства, мы увидим, что единственный способ выражения, разрешенный непосредственно в блоке, - это когда он является частью ExpressionStatement. Тем не менее, выражение ExpressionStatement явно определено , чтобы не начинаться с ключевого слова "function" , и именно поэтому FunctionDeclaration не может отображаться непосредственно в Statement или Block (обратите внимание, что Block - это всего лишь список операторов).

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

Также стоит процитировать проект ECMAScript 6 - B.3.3. Декларации функций уровня блока. Веб-совместимость. Семантика совместимости:

До шестого издания спецификация ECMAScript не определяла появление FunctionDeclaration как элемента блока Statement StatementList. Тем не менее, поддержка этой формы FunctionDeclaration была допустимым расширением, и большинство разрешенных ECMAScript версий браузера разрешали их. К сожалению, семантика таких объявлений отличается от этих реализаций. [...]


Поскольку ES5 не определяет поведение для деклараций функций внутри блоков, позволяя использовать проприетарные расширения, технически нет "прав" или "неправильных". Рассмотрим их "неуказанное поведение", которое не переносится в разных средах, совместимых с ES5.

В любом случае их легко переписать в переносимый код:

  • Если объявление функции должно быть поднято в верхней части текущей функции/глобальной области? Убедитесь, что объявление функции не находится непосредственно внутри блока.
  • Должна ли функция быть объявлена ​​только при выполнении блока? Назначьте выражение функции переменной (var f = function() {};). Обратите внимание, что нет подъема, и переменная по-прежнему доступна вне блока (объявления var являются областями с функциональным уровнем).

В соответствии с ECMAScript 6 объявления функций ограничены блоками, поэтому Firefox реализует правильное поведение ES6-мудрый.