32

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

这将显示“Hello world”:

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

但这会显示“ReferenceError: hello is not defined”:

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

因此,在函数声明方面,try 块显然有一些“特殊”之处。有没有办法解决这种行为?

4

3 回答 3

26

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

为什么 Firefox 对语句的解释不同是因为下面的代码:

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

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

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

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

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

生产 SourceElement:Statement 被处理为函数声明,不采取任何行动
生产 SourceElement : 语句的评估如下:

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

FunctionDeclaration 和 Statement 都是 SourceElements,因此,语句中不应该有 FunctionDeclarations(if/else,try/catch)。给 Šime Vidas 一块巧克力蛋糕!

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

于 2010-11-01T14:04:01.047 回答
5

鉴于功能块建立了具有前向函数引用的本地范围,将 try 块的内容包装在立即函数中似乎可以恢复该行为。

这适用于 Firefox、IE、Chrome:

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

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

于 2010-11-01T14:30:48.583 回答
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 内的任何垃圾上获得异常。

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

于 2010-11-01T14:47:57.130 回答