Возможно, вы нашли причуду в языке, и если вы посмотрите немного дальше, вы также найдете различные реализации.
Обработка ECMAScript состоит из двух этапов - на первом все объявления обрабатываются для создания именованных свойств в рамках их объявления. Во втором код выполняется. Таким образом, объявленные функции и переменные доступны в своей объявленной области с начала выполнения, независимо от того, где в коде они объявлены.
А те, которые созданы или им присвоены значения по присвоению, будут иметь значения только при выполнении кода присвоения.
Итак:
// Call x
x();
// Declare x
function x(){}
работает без ошибок. Это в разговорной речи называется «подъем», то есть объявления «поднимаются» в верхней части области.
Однако, перефразируя ваш пример:
if (true) {
function x(){
alert('true x');
}
} else {
function x(){
alert('false x');
}
}
// In most browsers
x(); // false x
// But in Firefox
x(); // true x
Для большинства браузеров второе объявление переопределяет первое. Это связано с тем, что ECMAScript не имеет области видимости блока, только функции и глобальной области видимости.
Однако , в этом случае расширения допускаются для языка. Firefox обрабатывает вышесказанное как выражения именованных функций, поэтому показывает true x
. Что еще более важно, поскольку другие браузеры обрабатывают выражения как объявления, x можно вызывать сверху блока кода, но в Firefox это невозможно, вы получите ошибку.
Суть в том, что если вы хотите условно назначить функцию для именованного параметра или переменной, сделайте это явно так:
var x;
if (true) {
x = function (){
alert('true x');
};
} else {
x = function (){
alert('false x');
};
}
чтобы вы получали последовательное поведение. И вы также должны помнить, что x не будет функцией до тех пор, пока после выполнения кода он не будет «поднят», потому что это не объявление.