Actually, why not a function, but only the block itself?

Tested in Chrome, FF, IE11 and Opera 12.

function test() { var e = 10, x = 5; try { console.log(e, x); // 10 5 throw 15; } catch (e) { var x; console.log(e, x); // 15 5 e = x = 17; console.log(e, x); // 17 17 } finally { console.log(e, x); // 10 17 } } test(); 

Well, ES6 version with decomposition:

 function test() { var e = 10, x = 5; try { console.log(e, x); // 10 5 throw {e: 15, x:3}; } catch ({e, x}) { console.log(e, x); // 15 3 e = x = 17; console.log(e, x); // 17 17 } finally { console.log(e, x); // 10 5 } } test(); 

  • 3
    JavaScript creates an e identifier upon entering the catch block and destroys it on exit. It overlaps the local variable e . Such is the peculiarity of the language. - Vladimir Gamalyan
  • @VladimirGamalian, is it written somewhere in the standard? - Qwertiy
  • es5.imtqy.com/#x12.14 3. Let catchEnv as the result of the call. 4. Call the CreateMutableBinding concrete method of catchEnv passing the Identifier String value as the argument. 5. Call the SetMutableBinding concrete method of catchEnv passing the Identifier, C and false as arguments. Note that the last argument is immaterial in this situation. 6. Set the running execution context of Lexical Environment to catchEnv. - Vladimir Gamalyan
  • one
    @VladimirGamalian, but doesn’t NewDeclarativeEnvironment mean your own scop? But catch doesn't have it? Or is it such magic due to the ascent of ads that all pops up except for the exception? Somehow weird turns out ... - Qwertiy
  • one
    @Qwertiy, the old question on EN: stackoverflow.com/questions/7926237/… - Grundy

2 answers 2

Refer to the specification :

Catch : catch ( CatchParameter ) Block

  1. oldEnv is saved LexicalEnvironment from the current context
  2. create catchEnv as a NewDeclarativeEnvironment (oldEnv) .
  3. MutableBinding is created for each argument name from BoundNames to CatchParameter in catchEnv
  4. The current LexicalEnvironment in the context is set to catchEnv.
  5. BindingInitialization result is saved in status .
  6. if status is not normal
    1. the current LexicalEnvironment in the context is set to oldEnv
    2. the catch value of the block is set to status
  7. B stores the result of the execution of a Block.
  8. the current LexicalEnvironment in the context is set to oldEnv
  9. the catch value of the block is set to B

What can be noted in this algorithm?

  1. when you enter catch , a new LexicalEnvironment is created
  2. the values ​​specified in the catch parameters are associated with the new LexicalEnvironment
  3. on exit, the old LexicalEnvironment is always restored

Thus e declared above var e=10 overlaps e in the expression catch (e) , the value of which is used inside the block.

And since the old LexicalEnvironment is restored when exiting the block, the variable declared through var will be visible inside the finally block.

Now you can go to the question from the comment:

@VladimirGamalian, but doesn’t NewDeclarativeEnvironment mean your own scop? But catch doesn't have it? Or is it such magic due to the ascent of ads that all pops up except for the exception? Somehow strange it turns out ...

In the execution context, there are two additional properties.

  • LexicalEnvironment - defines the Lexical Environment , which stores the identifiers created in the code in the current context
  • VariableEnvironment - defines the Lexical Environment in which the EnvironmentRecord stores the bindings created with VariableStatements in the current context

When using the var expression, variables are added to the VariableEnvironment of the current context. Since when entering a catch only LexicalEnvironment changes - it becomes irrelevant where the variable is declared with var - it will still be added to the VariableEnvironment and will be accessible from anywhere in the current execution context.

  • It's not about surfacing. Variables created with eval do not pop up, but such a variable from the catch block is still visible in the function below. This means that the binding goes exactly to the function's skoup and only the exception is tied to some special block. It is necessary to clarify and supplement this point somehow. - Qwertiy
  • @Qwertiy, Variables created with eval don't pop up - add code you don't quite understand - Grundy
  • var a = 1, b = 2, c = 3, d = 4; (function () { console.log(a, b, c, d); var a = 11; eval('var b = 12'); console.log(a, b, c, d); try { throw 0 } catch (e) { var c = 13; eval('var d = 14'); console.log(a, b, c, d); } console.log(a, b, c, d); })(); At first we see 2 and 4 from the upper region, 1 and 3 are covered by declared vars. Then the variable b = 12 is created in runtime and it overlaps the external one. And then, in the catch block, c = 14 is created in the same way. It is visible outside the catch block, which means that even in runtime, the binding goes to the function's skoup, and not to the skip to which the exception is bound. - Qwertiy
  • Even so - here it can be seen that the global value was not spoiled: var a = 1, b = 2, c = 3, d = 4; (function () { console.log(a, b, c, d); var a = 11; eval('var b = 12'); console.log(a, b, c, d); try { throw 0 } catch (e) { var c = 13; eval('var d = 14'); console.log(a, b, c, d); } console.log(a, b, c, d); a = 21, b = 22, c = 23, d = 24; console.log(a, b, c, d); })(); console.log(a, b, c, d); var a = 1, b = 2, c = 3, d = 4; (function () { console.log(a, b, c, d); var a = 11; eval('var b = 12'); console.log(a, b, c, d); try { throw 0 } catch (e) { var c = 13; eval('var d = 14'); console.log(a, b, c, d); } console.log(a, b, c, d); a = 21, b = 22, c = 23, d = 24; console.log(a, b, c, d); })(); console.log(a, b, c, d); - Qwertiy
  • @Qwertiy :-) I did not understand that it is in this code that contradicts the answer :-) but the whole point is how the variables are declared. When a variable is declared via var , it is found in a VariableEnvironment , which is rather rarely created: when entering the script tag, in a module, in a function. And in catch , LexicalEnvironment is created - this is the same, but a little different :-) and it is already created at the block level, so after adding it even with the help of the eval variable in the VariableEnvironment, it becomes visible everywhere where this Environment is visible - Grundy

The catch block creates a copy of the object created by the throw operator, and finally has access to the object external to the catch that has not changed.

Update

In catch, a temporary nameless object created by throw is passed, the fields of which move to the global object and overlap the variables e and x. Upon exiting the catch, it is destroyed, so the finally e and x functions declared at the beginning are displayed.

  • one
    Copy object? o_O You're not confused language? To an external object? Immediately there is a general discussion of variables ... - Qwertiy
  • Yes Yes. But I’m pretty sure that the names in the catch block overlap with the appearance of external visibility. Could understand ... Object? And what about your not object in JS? - cipher_web
  • He has no scope for anything except an exception. - Qwertiy
  • @Qwertiy, look at the link, there they say that catch by analogy with with - Grundy
  • <pre> <code> throw {e: 15, x: 3}; </ code> </ pre> So about this and that ... - cipher_web