0

Объявления функций внутри операторов if/else?

12

Как обрабатываются объявления функций в JavaScript?

У меня возникла проблема с объявлениями функций в JavaScript, которые ведут себя по-разному в разных браузерах. Рассмотрим следующий код:

var abc = '';
if (1 === 0) {
  function a() {
    abc = 7;
  }
} else if ('a' === 'a') {
  function a() {
    abc = 19;
  }
} else if ('foo' === 'bar') {
  function a() {
    abc = 'foo';
  }
}
a();
document.write(abc); // выводит "foo", хотя 'foo' !== 'bar'

При выполнении этого кода в Chrome и Firefox я получаю разные результаты: Chrome выводит foo, тогда как Firefox выводит 19.

Я пытаюсь понять, почему так происходит, и как именно в JavaScript обрабатываются объявления функций в ветвлении условий. Почему разные браузеры выводят разные значения? Какие правила здесь действуют?

3 ответ(ов)

0

В JavaScript существуют два основных способа объявления функций: декларации функций и выражения функций.

Декларация функции:

function foo() {
}

Выражение функции:

var foo = function() {
}

Как указывает ресурс Adequately Good:

“Декларации функций и переменные функции всегда перемещаются (или «поднимаются») в верхнюю часть области видимости JavaScript интерпретатором.”

Это означает, что в первом примере декларация функции function a() поднимается в область видимости JavaScript, что позволяет использовать foo, даже если условие if не выполнено.

Сравните var foo с обычным выражением JavaScript; оно выполняется только во время выполнения вашего кода, в отличие от function foo(). Это объясняет, почему следующий код работает:

alert(foo());

function foo() {
   return 'gw ganteng';
}

В данном случае function foo() обрабатывается парсером, и foo() попадает в текущую область видимости до того, как JavaScript пытается вызвать alert(foo()).

Также стоит отметить, что в JavaScript есть контекст (который ECMA 5 разбивает на LexicalEnvironment, VariableEnvironment и ThisBinding) и процесс (набор операторов, которые выполняются последовательно). Декларации влияют на VariableEnvironment при входе в область выполнения. Они отличаются от операторов (таких как return) и не подчиняются их правилам.

0

ECMA-262 версии 5 требует, чтобы реализации регистрировали все объявления функций и переменных во время первого прохода при входе в любой новый глобальный или функциональный контекст выполнения. В данном случае Chrome технически прав, так как он просматривает блоки else и then, регистрируя a() до выполнения. К сожалению, это приводит к наименее читаемым результатам.

Firefox же дожидается оценки условного оператора if, прежде чем добавлять объявления функций и переменных в текущий контекст. Кстати, оба браузера действуют аналогично в блоках catch и finally.

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

0

Объявления функций недоступны за пределами `

if (true) {
  function sayHi() {
    alert("hii");
  }
  sayHi(); // доступно
}

sayHi(); // ошибка, недоступно, так как за пределами блока

Если вы хотите определять функции условно, используйте функциональные выражения, такие как:

let sayHi;
if (true) {
  sayHi = function() {
    alert("hii");
  }
  sayHi(); // доступно
}

sayHi(); // доступно

Такое поведение связано с тем, что функции, объявленные с помощью function, имеют подъем (hoisting) в пределах блока if, тогда как функциональные выражения привязываются к переменной и могут быть использованы после их инициализации.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь