为什么我不能在try块中定义之前使用Javascript函数?

时间:2010-11-01 13:04:47

标签: javascript firefox function try-catch forward-declaration

正如所讨论的here,函数定义可以在定义之前使用。但是只要一段代码被包装在try块中,就不会出现这种情况了。

显示“Hello world”:

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

但显示“ReferenceError:hello未定义”:

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

因此,关于函数声明的try块显然有一些“特殊”。有没有办法绕过这种行为?

3 个答案:

答案 0 :(得分:26)

Firefox以不同的方式解释函数语句,显然它们打破了函数声明的声明提升。 (A good read about named functions / declaration vs expression

为什么Firefox不同地解释语句是因为以下代码:

if ( true ) {
    function test(){alert("YAY");}
} else {
    function test(){alert("FAIL");}
}
test(); // should alert FAIL

由于声明提升,函数test应始终警告“失败”,但不是在Firefox中。上面的代码实际上警告了Firefox中的“YAY”,我怀疑使这种情况发生的代码最终完全破坏了声明。

我假设Firefox将函数声明转换为var声明,当它们位于if / else或try / catch语句中时。像这样:

// firefox interpretted code
var test; // hoisted
if (true) {
   test = function(){alert("yay")}
} else {
   test = function(){alert("fail")}
}

在与ŠimeVidas进行简短辩论之后,我不得不说Firefox处理函数声明是非标准的,因为:

  

生产SourceElement:   语句处理功能   声明不采取任何行动   生产SourceElement:Statement   评估如下:

     
      
  1. 评估声明。
  2.   
  3. 返回结果(1)。
  4.   

FunctionDeclaration和Statement都是SourceElements,ergo,语句中应该没有FunctionDeclarations(if / else,try / catch)。给ŠimeVidas一个布朗尼!

try / catch基本上是if / else的另一种形式,可能使用相同的异常代码。

答案 1 :(得分:5)

假设一个功能块使用正向函数引用建立一个本地作用域,则将try块的内容包装在一个立即函数中似乎可以恢复该行为。

适用于Firefox,IE,Chrome:

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

当然,try-function中定义的函数和变量在catch块中不再可见,因为它们没有立即的函数包装器。但这是try / catch脚本包装的可能解决方法。

答案 2 :(得分:1)

你总是可以这样做,并充分利用这两个方面:

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);
}

这将按预期工作,没有解析问题。它在加载时可能失败的唯一位置在函数defs和try catch之外。您还将获得函数defs内的任何垃圾的例外。

我想这是一种风格偏好,但它似乎比其他选项更具可读性和可维护性。