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

Почему я не могу использовать функцию 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 относительно объявлений функций. Есть ли способ обойти это поведение?

4b9b3361

Ответ 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.

Я предполагаю, что это предпочтение стиля, но оно кажется более читабельным и удобным для меня, чем другие варианты.