Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript catch clause scope

Tags:

javascript

The ECMAScript 5 spec states the following:

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.

If my understanding is correct, then when a new Lexical Environment is created in JavaScript, a new scope is entered, which is why variables declared inside a function are not visible outside of that function:

function example() {
    var x = 10;
    console.log(x); //10
}
console.log(x); //ReferenceError

So in the above function declaration, a new Lexical Environment is created, which means x is not available in any outer Lexical Environments that may exist.

So the part of the quote above about Function Declarations seems to make sense. However, it also states that a new Lexical Environment is created for the Catch clause of a Try Statement:

try {
    console.log(y); //ReferenceError so we enter catch
} 
catch(e) {
    var x = 10;
    console.log(x); //10
}
console.log(x); //10 - but why is x in scope?

So how does the scope of a catch block work? Do I have a fundamental misunderstanding of what a Lexical Environment is?

like image 311
James Allardice Avatar asked Oct 28 '11 07:10

James Allardice


People also ask

How do you use a try block variable in catch block?

Variables in try block So, if you declare a variable in try block, (for that matter in any block) it will be local to that particular block, the life time of the variable expires after the execution of the block. Therefore, you cannot access any variable declared in a block, outside it.

Can you nest try catch blocks JavaScript?

You can nest one or more try statements. If an inner try statement does not have a catch -block, the enclosing try statement's catch -block is used instead. You can also use the try statement to handle JavaScript exceptions. See the JavaScript Guide for more information on JavaScript exceptions.

Is it bad to use try catch in JavaScript?

The try-catch statement should be used any time you want to hide errors from the user, or any time you want to produce custom errors for your users' benefit. If you haven't figured it out yet, when you execute a try-catch statement, the browser's usual error handling mechanism will be disabled.

When to use try and catch JavaScript?

The try statement allows you to define a block of code to be tested for errors while it is being executed. The catch statement allows you to define a block of code to be executed, if an error occurs in the try block.


3 Answers

If I understand it right, then what it probably means is that, in your code,

try {
    console.log(y); //ReferenceError so we enter catch
} 
catch(e) {
    var x = 10;
    console.log(x); //10
}

e will only exist in the catch block. Try console.log(e); outside the catch block and it will throw ReferenceError.

As with WithStatement, with ({x: 1, y: 2}) { }, x and y will only exist inside the with block.

But it doesn't mean that var declarations will be bound to the closest lexical environment. Actually, var declarations will be bound to the environment when entering an execution context.

10.5 Declaration Binding Instantiation: when the execution context in being entered, it will look for function declarations, arguments, and variable declarations and then create bindings in the execution context's VariableEnvironment.

So any variables that are declared using var will be accessible anywhere in the function regardless of the control structures or where it is defined inside the function. Note that this does not include nested functions as they're a separate execution context.

That means the var declarations will be bound to the closest execution context.

var x = 1;
(function() {
    x = 5; console.log(x); // 5
    if (false) { var x; }
    x = 9; console.log(x); // 9
})();
console.log(x); // 1

So in above code, x = 5; will set the x variable inside the inner function, because var x; inside if (false) { var x; } is bound to that function already before the function code is executed.

like image 176
Thai Avatar answered Oct 23 '22 11:10

Thai


From dev.opera (emphasis added)

The try-catch-finally construct is fairly unique. Unlike other constructs, it creates a new variable in the current scope at runtime. This happens each time the catch clause is executed, where the caught exception object is assigned to a variable. This variable does not exist inside other parts of the script even inside the same scope. It is created at the start of the catch clause, then destroyed at the end of it.

So it looks like the only thing that's really within the scope of the catch is the exception itself. Other actions seem to be (or stay) bound to the outer scope of the catch (so in the example the global scope).

try {
    console.log(y); //ReferenceError so we enter catch
}
catch(e) {
    var x = 10;
    console.log(x); //10
}
console.log(e.message); //=> reference error

In ES5 these lines may be relevant (bold/emphasis added) to this:

  1. Let oldEnv be the running execution context’s LexicalEnvironment.
  2. Let catchEnv be the result of calling NewDeclarativeEnvironment passing oldEnv as the argument.

Also at the end of that part it states:

NOTE: No matter how control leaves the Block the LexicalEnvironment is always restored to its former state

like image 35
KooiInc Avatar answered Oct 23 '22 11:10

KooiInc


Since it was standardized in ES3, a catch () {} clause is (to my knowledge) the only pre-ES2015 javascript construct that creates a block-level scope, simply because it is the only block-level construct that comes with an argument.

It is the reason why it's been used as a polyfill by next-generation javascript transpilers to compile this:

ES2015:

{ let priv = 1; }
console.log(priv); // throws ReferenceError

to this:

ES5 and lower:

try { throw void 0 } catch (priv) { priv = 1 }
console.log(priv); // throws ReferenceError
like image 7
Christophe Marois Avatar answered Oct 23 '22 10:10

Christophe Marois