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

Why can't I use a Javascript function before its definition inside a try block?

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

这显示"Hello world":

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

但是这会显示"ReferenceError:hello is not defined":

1
2
3
4
5
6
try {
  hello();
  function hello() { alert("Hello world"); }
} catch (err) {
  alert(err);
}

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


Firefox以不同的方式解释函数语句,显然它们破坏了函数声明的声明提升。 (关于命名函数/声明vs表达的好读物)

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

1
2
3
4
5
6
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语句中时。像这样:

1
2
3
4
5
6
7
// firefox interpretted code
var test; // hoisted
if (true) {
   test = function(){alert("yay")}
} else {
   test = function(){alert("fail")}
}

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

The production SourceElement :
Statement is processed for function
declarations by taking no action.
The production SourceElement : Statement
is evaluated as follows:

  • Evaluate Statement.
  • Return Result(1).
  • 函数声明和声明都是SourceElements,因此,声明中应该没有FunctionDeclarations(if / else,try / catch)。给我?维达斯一个布朗尼!

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


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

    这适用于Firefox,IE,Chrome:

    1
    2
    3
    4
    5
    6
    7
    8
    try {
      (function(){
        hello();
        function hello() { alert("Hello world"); }
      }())
    } catch (err) {
      alert(err);
    }

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


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function hello() {
      alert("Hello world");
    }

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

    您仍将在catch块中获取异常,但该函数将可用。它也应该更容易维护,并且无论如何提升功能都没有功能上的好处。

    编辑:

    为了证明这与在try catch中包含整个代码一样耐用,我提供了一个更详细的例子。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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内部任何垃圾的例外情况。

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