请考虑以下摘录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
子句需要自己的词法环境?
答案 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中不再是这样,其中块级函数声明有效且在块范围内关闭)