bfa*_*tto 5 javascript scope try-catch ecmascript-5 hoisting
请考虑ECMA-262 v5.1的以下摘录(我最近在这个问题中看到过):
词汇环境是一种规范类型,用于根据ECMAScript代码的词法嵌套结构定义标识符与特定变量和函数的关联.词汇环境由环境记录和外部词汇环境的可能空引用组成.通常,词汇环境与ECMAScript代码的某些特定语法结构相关联,例如TryStatement的FunctionDeclaration,WithStatement或Catch子句,并且每次评估此类代码时都会创建新的词法环境.
我认为这意味着catch子句的主体会像函数那样提升自己的变量,但显然情况并非如此:
var a = 1;
try {
console.log(x); // ReferenceError
} catch(ex) {
console.log(a); // 1, not undefined
var a = 3;
}
Run Code Online (Sandbox Code Playgroud)
有人知道为什么吗?另外,为什么一个catch条款需要自己的词汇环境?
是的,catch条款确实有自己的词汇环境.查看评估时会发生什么:它创建一个新的(从当前的一个派生)并将异常标识符绑定到它.执行catch块时,当前执行上下文 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
}
Run Code Online (Sandbox Code Playgroud)
有趣的事实:如果你试图在一个子句中声明一个函数catch(虽然在块中语法无效,经常接受"函数声明语句"),它的作用域将成为当前的,VariableEnvironment因此它将无法访问异常:
try {throw "some"} catch(x) { function y(){console.log(x, typeof x);} y(); }
// throws a ReferenceError for x ^
Run Code Online (Sandbox Code Playgroud)
(更新:在ES6中不再是这样,其中块级函数声明有效并且在块范围内关闭)