为什么catch子句有自己的词汇环境?

时间:2013-02-22 23:19:49

标签: javascript scope try-catch ecmascript-5 hoisting

请考虑以下摘录from ECMA-262 v5.1(我最近在this question中看到过):

  

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

我认为这意味着catch子句的主体会像函数一样提升自己的变量,但显然that's not the case

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

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

1 个答案:

答案 0 :(得分:6)

是的,catch条款确实有自己的词法环境。查看happens when it is evaluated:它创建一个新的(从当前的一个派生)并将异常标识符绑定到它。执行catch块时,当前Execution Context's LexicalEnvironment将切换为新的VariableEnvironment(“”,其环境记录包含由VariableStatements创建的绑定, FunctionDeclarations “)保持不变。

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中不再是这样,其中块级函数声明有效且在块范围内关闭)