6

考虑以下来自 ECMA-262 v5.1的摘录(我最近在这个问题中看到):

词法环境是一种规范类型,用于根据 ECMAScript 代码的词法嵌套结构定义标识符与特定变量和函数的关联。一个词法环境由一个环境记录和一个对外部词法环境的可能为空的引用组成。通常,词法环境与 ECMAScript 代码的某些特定句法结构相关联,例如 FunctionDeclaration、WithStatement 或 TryStatement 的 Catch 子句,并且每次评估此类代码时都会创建一个新的词法环境。

我认为这意味着catch子句的主体会像函数一样提升自己的变量,但显然情况并非如此

var a = 1;
try {
    console.log(x); // ReferenceError
} catch(ex) {
    console.log(a); // 1, not undefined
    var a = 3;
}

有人知道为什么吗?另外,为什么一个catch子句需要它自己的词法环境?

4

1 回答 1

9

是的,catch子句确实有自己的词法环境。查看评估时会发生什么:它创建一个新的(从当前的派生)并将异常标识符绑定到它。执行 catch 块时,当前的执行上下文 LexicalEnvironment切换到新的执行上下文,而VariableEnvironment("其环境记录保存由VariableStatementsandFunctionDeclarations " 创建的绑定) 保持不变。

console.log(a); // undefined - declared from within the catch,
                // but in the current VariableEnvironment
a = 1;
console.log(typeof ex); // undefined - no binding
try {
    console.log(ex); // a ReferenceError in this LexicalEnvironment
} catch (ex) { // introducing the new LexicalEnvironment
    console.log(ex); // …and it works here!
    var a = 3; // variable declaration
}

有趣的事实:如果你试图在一个子句中声明一个函数catch(尽管在一个块中语法无效,“函数声明语句”通常被接受),它的作用域将变成当前的VariableEnvironment,因此它不能访问异常:

try {throw "some"} catch(x) { function y(){console.log(x, typeof x);} y(); }
                    // throws a ReferenceError for x   ^

(更新:这在 ES6 中不再适用,其中块级函数声明是有效的并且在块范围内是封闭的)

于 2013-02-22T23:38:17.283 回答