Почему я не могу использовать функцию Javascript перед ее определением внутри блока try?
Как обсуждалось здесь, определения функций могут использоваться до их определения. Но как только часть кода будет завершена в блок try, это перестает быть.
Отображается "Hello world":
hello();
function hello() { alert("Hello world"); }
Но это отображает "ReferenceError: hello не определено":
try {
hello();
function hello() { alert("Hello world"); }
} catch (err) {
alert(err);
}
Таким образом, есть явно что-то особенное о блоке try относительно объявлений функций. Есть ли способ обойти это поведение?
Ответы
Ответ 1
Учитывая, что функциональный блок устанавливает локальную область с привязкой к прямой функции, обертывание содержимого блока try в непосредственной функции, похоже, восстанавливает это поведение.
Это работает в Firefox, IE, Chrome:
try {
(function(){
hello();
function hello() { alert("Hello world"); }
}())
} catch (err) {
alert(err);
}
Конечно, функции и переменные, определенные в try-функции, больше не видны в блоке catch, так как они не будут иметь операционную оболочку. Но это возможное обходное решение для обертывания try/catch script.
Ответ 2
Firefox интерпретирует операторы функций по-разному и, по-видимому, они сломали объявление для объявления функции. (Хорошее чтение о названных функциях/декларации vs выражение)
Почему Firefox интерпретирует заявления по-разному из-за следующего кода:
if ( true ) {
function test(){alert("YAY");}
} else {
function test(){alert("FAIL");}
}
test(); // should alert FAIL
Из-за подъема объявления функция test
должна всегда предупреждать "сбой", но не в Firefox. Вышеупомянутый код фактически предупреждает "YAY" в Firefox, и я подозреваю, что код, который делает это, наконец-то сломал объявление, поднимающее вообще.
Я предполагаю, что Firefox превращает объявления функций в объявления var, когда они находятся в операциях if/else или try/catch. Например:
// firefox interpretted code
var test; // hoisted
if (true) {
test = function(){alert("yay")}
} else {
test = function(){alert("fail")}
}
После коротких дебатов с Šime Vidas я должен сказать, что Firefox, занимающийся объявлениями функций, нестандартен, из-за:
Источник SourceElement: Оператор обрабатывается для функции объявления , не предпринимая никаких действий.
Производство SourceElement: Statement оценивается следующим образом:
- Вычислить выражение.
- Результат возврата (1).
Оба FunctionDeclaration и Statement являются SourceElements, ergo, внутри оператора не должно быть FunctionDeclarations (if/else, try/catch). Дайте Šime Vidas домохозяйку!
Try/catch - это в основном другая форма if/else и, вероятно, использует тот же код исключения.
Ответ 3
Вы всегда можете сделать это так и получить лучшее из обоих миров:
function hello() {
alert("Hello world");
}
try {
hello();
}
catch (err) {
alert(err);
}
Вы все равно получите свои исключения в блоке catch, но функция будет доступна. Это также должно быть проще в обслуживании, и в любом случае функциональных преимуществ для функций подъема не существует.
Edit:
Чтобы продемонстрировать, что это так же долговечно, как обертывание всего кода в попытке catch, я предоставляю более подробный пример.
function hello(str) {
alert("Hello, " + str);
}
function greet() {
asdf
}
try {
var user = "Bob";
hello(user);
greet();
asdf
}
catch (e) {
alert(e);
}
Это будет работать, как ожидалось, без проблем с синтаксическим разбором. Единственные места, где он может выйти из строя во время загрузки, находятся за пределами функции defs и try catch. Вы также получите исключения из любого мусора внутри функции defs.
Я предполагаю, что это предпочтение стиля, но оно кажется более читабельным и удобным для меня, чем другие варианты.