Объявление функций внутри операторов 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
.
Ответы
Ответ 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, связанных с функцией, которой не следует начинать. В приведенном ниже сценарии показано, почему декларации функций не должны находиться внутри операторов потока управления.