Почему я не могу использовать функцию Javascript до ее определения внутри блока try? - PullRequest
32 голосов
/ 01 ноября 2010

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

Отображается «Hello world»:

hello();
function hello() { alert("Hello world"); }

Но отображается «ReferenceError:hello не определен ":

try {
  hello();
  function hello() { alert("Hello world"); }
} catch (err) {
  alert(err);
}

Так что в блоке try явно есть что-то" особенное "в отношении объявлений функций.Есть ли способ обойти это поведение?

Ответы [ 3 ]

26 голосов
/ 01 ноября 2010

Firefox по-разному интерпретирует операторы функций и, по-видимому, они нарушили объявление для объявления функций. ( Хорошее чтение об именованных функциях / объявлении против выражения )

Почему 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")}
}

После короткой дискуссии с Шиме Видасом я должен сказать, что работа Firefox с объявлениями функций нестандартна из-за:

SourceElement производства: Заявление обрабатывается для функции декларации , не предпринимая никаких действий .
Производство SourceElement: Заявление оценивается следующим образом:

  1. Оценка заявления.
  2. Результат возврата (1).

И FunctionDeclaration, и Statement являются SourceElements, следовательно, внутри оператора не должно быть FunctionDeclarations (if / else, try / catch). Дайте Шиме Видасу пирожное!

Try / catch - это, по сути, еще одна форма if / else, и, вероятно, она использует тот же код исключения.

5 голосов
/ 01 ноября 2010

Учитывая, что функциональный блок устанавливает локальную область с прямой ссылкой на функцию, завершение содержимого блока try в немедленной функции, похоже, восстанавливает такое поведение.

Это работает в Firefox, IE, Chrome:

try {
  (function(){
    hello();
    function hello() { alert("Hello world"); }
  }())
} catch (err) {
  alert(err);
}

Конечно, функции и переменные, определенные в try-функции, больше не видны в блоке catch, как это было бы без непосредственного упаковщика функций. Но это возможный обходной путь для переноса сценария try / catch.

1 голос
/ 01 ноября 2010

Вы всегда можете сделать это таким образом и получить лучшее из обоих миров:

function hello() {
  alert("Hello world");
}

try {
  hello();
}
catch (err) {
  alert(err);
}

Вы все равно получите свои исключения в блоке catch, но функция будет доступна.Это также должно быть проще в обслуживании, и в любом случае нет никакой функциональной выгоды для подъемных функций.

Редактировать:

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

function hello(str) {
  alert("Hello, " + str);
}

function greet() {
  asdf
}

try {
  var user = "Bob";
  hello(user);
  greet();
  asdf
}
catch (e) {
  alert(e);
}

Это будет работать, как и ожидалось, без проблем с синтаксическим анализом.Единственные места, где он может потерпеть неудачу во время загрузки, находятся вне функций def и try catch.Вы также получите исключения для любого мусора внутри функции def.

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

...