1

I have this code:

(function() {
   var ex;
   try {
       throw new Error('blah');
   } catch(ex) {
       console.log('ex i here:', ex);
   }
   console.log('ex out here:', ex);

   return 'hi';
})()

This logs:

ex i here: Error('blah');

ex out here: undefined

Why is this so? I would think due to hoisting, ex would get set outside of this block scope, so it should be available in ex out here.

I expected it to work similar to a for loop:

for (i=0; i<2; i++) {
}
console.log(i); // gives 2
Noitidart
  • 35,443
  • 37
  • 154
  • 323
  • 3
    `catch(ex)` That `ex` there is scoped for you. – Keith Mar 28 '19 at 16:22
  • 1
    Possible duplicate of [JavaScript catch clause scope](https://stackoverflow.com/questions/7926237/javascript-catch-clause-scope) – Kirk Larkin Mar 28 '19 at 16:22
  • 4
    `ex` in catch is not a declared var, it's a parameter, it actually shadows your `ex` var – Kaddath Mar 28 '19 at 16:23
  • [13.15 The `try` Statement](https://www.ecma-international.org/ecma-262/6.0/#sec-try-statement): _"The `catch` clause provides the exception-handling code. When a `catch` clause catches an exception, its CatchParameter is bound to that exception."_ – Andreas Mar 28 '19 at 16:26
  • You never defined `ex` only declared it. The one in the catch is the parameter `ex` not the variable you declared – Huangism Mar 28 '19 at 16:26
  • 1
    @KirkLarkin I don't think so... It isn't about the exception 'parameter variable' – FZs Mar 28 '19 at 16:28
  • @Kaddath can you please explain what it means to shadow. I'm not understanding this. I added an example of the for loop which does affect the hoisted. – Noitidart Mar 28 '19 at 16:28
  • Thanks @FZs - I also think it's different, I'm in the catch statement unlike that topic. – Noitidart Mar 28 '19 at 16:29
  • 2
    @Noitidart shadowing means the parameters is a different variable that one in an outside scope. Even though they have the same name, the parameter is distinct and you no longer have access to the variable of the same name from the outer scope. In your example the two variables named `ex` are two distinct variables -- one in the outer scope and one the is a parameter. – Mark Mar 28 '19 at 16:30

3 Answers3

3

You are messing few things up.

Variables that are defined as var have function-scope. The parameter in catch is not hoisted, it has block-scope (only in that catch part).

As you can see in this example: The ab is hoisted and then is accessible outside the catch part. The ex2 does not exist outside the context.

(function() {
   var ex;
   try {
       throw new Error('blah');
   } catch(ex2) {
       var ab = 3;
       console.log('ex is here:', ex2.message);
   }
   console.log(ab);
   console.log(ex2);
   console.log('ex out here:', ex);

   return 'hi';
})()

In your example, there is different variable created with the same name, but different scope. If this happens, then (in almost all languages) the "deepest" variable in your context is used. If you want to take the error outside of catch with hositing, you can:

(function() {
   try {
       throw new Error('blah');
   } catch(ex2) {
       var ex = ex2;
       console.log('ex is here:', ex2.message);           
   }
   console.log(ex.message);

   return 'hi';
})()
libik
  • 22,239
  • 9
  • 44
  • 87
  • This is awesome thank you. I was trying to get the variable available outside of the scope. And was confused why no hoisting was happening. – Noitidart Mar 28 '19 at 16:53
2

This code behaves like this

  (function() {
   var ex1;
   try {
       throw new Error('blah');
   } catch(ex2) {
       console.log('ex i here:', ex2);
   }
   console.log('ex out here:', ex1);

   return 'hi';
  })()

That is because the second the ex declared in the catch is only visible to the catch's scope, for more information visit


Regarding the loop, in those iterations, js looks for the variable "i" declaration of the closest scope that contains it, which in this case is the parent, so the variable "i" that is changing is the one declared at the beggining as there is no variable declaration inside de loop.

Tabare
  • 151
  • 3
0

From try ... catch statement:

When an exception is thrown in the try block, exception_var (e.g., the e in catch (e)) holds the value specified by the throw statement. You can use this identifier to get information about the exception that was thrown. This identifier is local to the catch clause. That is, it is created when the catch clause is entered, and after the catch clause finishes executing, the identifier is no longer available.

Nina Scholz
  • 376,160
  • 25
  • 347
  • 392