Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do catch clauses have their own lexical environment?

Consider the following excerpt from ECMA-262 v5.1 (which I recently saw in this question):

A Lexical Environment is a specification type used to define the association of Identifiers to specific variables and functions based upon the lexical nesting structure of ECMAScript code. A Lexical Environment consists of an Environment Record and a possibly null reference to an outer Lexical Environment. Usually a Lexical Environment is associated with some specific syntactic structure of ECMAScript code such as a FunctionDeclaration, a WithStatement, or a Catch clause of a TryStatement and a new Lexical Environment is created each time such code is evaluated.

I thought that meant the body of catch clauses would hoist its own variables like functions do, but apparently that's not the case:

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

Does anybody know why? Also, why does a catch clause need its own lexical environment?

like image 529
bfavaretto Avatar asked Feb 22 '13 23:02

bfavaretto


People also ask

What does lexical environment mean?

A lexical environment is a data structure that holds identifier-variable mapping. (here identifier refers to the name of variables/functions, and the variable is the reference to actual object [including function object or primitive value]. Lexical in general means in hierarchy or in a sequence.

Is lexical environment the same as scope?

Lexical Environment is the environment of the function where it is written. That is, the static order/place where it is situated, regardless from where it is called from. Scope of a variable/function is basically the locations from where a variable is visible/accessible.


1 Answers

Yes, catch clauses indeed have their own Lexical Environments. Check out what happens when it is evaluated: It creates a new one (deriving from the current one) and binds the exception-identifier to it. When executing the catch block, the current Execution Context's LexicalEnvironment is switched to the new one, while the VariableEnvironment("whose environment record holds bindings created by VariableStatements and FunctionDeclarations") stays unchanged.

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
}

Fun fact: If you try to declare a function inside a catch clause (though syntactically invalid in a block, "function declaration statements" are often accepted), its scope will become the current VariableEnvironment so it will not be able to access the exception:

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

(Update: this is no longer true in ES6, where block-level function declarations are valid and close over the block scope)

like image 95
Bergi Avatar answered Oct 11 '22 13:10

Bergi