Scope of the exception in the catch block

Actually, why not the 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, the 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();

2 answers

Let's turn to the specification:

Catch : catch ( CatchParameter ) Block

  1. in oldEnv is stored LexicalEnvironment from the current context
  2. creates catchEnv as NewDeclarativeEnvironment(oldEnv).
  3. for each argument name from BoundNames to CatchParameter to catchEnv is created MutableBinding
  4. the current LexicalEnvironment in the context is set to catchEnv
  5. in status, the result of BindingInitialization
  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 executing Block.
  8. the current LexicalEnvironment in the context is set to oldEnv
  9. the value of the catch block is set to B

What can be noted in this algorithm?

  1. when entering catch, a new LexicalEnvironment
  2. values specified in the parameters catch bind to the new LexicalEnvironment
  3. when exiting - always the old LexicalEnvironment

Thus, the e declared above var e=10 overrides 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 via finally will be visible inside the block. var.

Now you can go to the question from the comment:

@VladimirGamalian, doesn't NewDeclarativeEnvironment mean your own scope? But catch doesn't have one, does it? Or is it such magic due to the surfacing of ads that everything pops up except for the exception? It's kind of weird...

In the execution context, there are two additional properties

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

When using the expression var variables are added to the VariableEnvironment of the current context. Since when entering catch, only the following changes: LexicalEnvironment - then it doesn't matter where the variable is declared with var - it will still be added to VariableEnvironment and will be available from anywhere in the current execution context.

 4
Author: Grundy, 2016-08-31 05:56:32

In the catch block, a copy of the object created by the throw statement is created, while finally has access to an object external to catch that has not changed.

Update

A temporary unnamed object created by throw is passed to catch, the fields of which move to the global object and overlap the variables e and x. When it exits catch, it is destroyed, so finally outputs the functions e and x declared at the beginning.

 -1
Author: cipher_web, 2016-08-17 04:30:52