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

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

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

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); //writes "foo" even though 'foo' !== 'bar'

В этом примере отображаются разные результаты в Chrome и Firefox. Выходы Chrome foo, в то время как выходы FF 19.

4b9b3361

Ответ 1

Когда этот вопрос был задан, был распространен ECMAScript 5 (ES5). В строгом режиме ES5 объявления функций не могут быть вложены внутри блока if как показано в вопросе. В нестрогом режиме результаты были непредсказуемыми. В разных браузерах и механизмах реализованы собственные правила для того, как они будут обрабатывать объявления функций внутри блоков.

Начиная с 2018 года, многие браузеры поддерживают ECMAScript 2015 (ES2015) в той мере, в которой объявления функций теперь разрешены внутри блоков. В среде ES2015 внутри этого блока будет помещено объявление функции внутри блока. Код в вопросе приведет к неопределенной ошибке функции, потому что функция a объявляется только в рамках операторов if и поэтому не существует в глобальной области.

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

Ответ 2

От http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/

В javascript у вас есть объявление функции:

function foo() {
}

и выражение функции

var foo = function() {
}

Цитата из http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

"Объявления функций и функциональные переменные всегда перемещаются (" Поднял ") в начало своей области JavaScript с помощью JavaScript переводчик".

Итак, что произошло в первом примере, это объявление функции function a(), которое поднимается вверху области Javascript, создавая таким образом foo, даже если значение if оценивается как false

Вспомните var foo как обычный Javascript-оператор, он выполняется только во время выполнения вашего javascript, в отличие от function foo(), поэтому верно следующее:

alert(foo());

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

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

http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/

При выполнении JavaScript есть Контекст (который ECMA 5 врывается в LexicalEnvironment, VariableEnvironment и ThisBinding) и Process (набор операторов, вызываемых последовательно). Объявления вносить вклад в переменную среду, когда область выполнения вошел. Они отличаются от заявлений (например, возврата) и являются не подчиняясь их правилам процесса.

Ответ 3

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

FF ожидает, пока он оценит оператор if перед его вычислением и добавит объявления функций и переменных в текущий контекст. КСТАТИ. Оба браузера делают это так внутри catch и finally clauses.

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