Smelly Code

Variable Scope in Catch Block ~ JavaScript

August 02, 20193 min 👓

Variable scope and hoisting are notorious in JavaScript land. Both newbies and seasoned programmers have difficulties to wrap their head around these when they encounter certain quirks. A few weeks ago, Kyle Simpson tweeted below code snippet with TIL caption.

function foo() {
  'use strict';
  err = 1;
  try {
    throw 'hello';
  } catch (err) {
    console.log(err);
    var err = 2;
  }
  console.log(err);
}
foo();

When I interpreted the code, I concluded the output below.

hello
2

Sadly my interpretation was incorrect. The actual output is.

hello
1

The enigma of variables within the catch block made me curious to take a gander at the spec. I found this note:

The Block of a Catch clause may contain var declarations that bind a name that is also bound by the CatchParameter. At runtime, such bindings are instantiated in the VariableDeclarationEnvironment. They do not shadow the same-named bindings introduced by the CatchParameter and hence the Initializer for such var declarations will assign to the corresponding catch parameter rather than the var binding.

In simple words, the catch parameter is block-scoped—can not be accessed outside the block. And, it overrides/shadows variables with the same name.

function foo() {
  'use strict';
  try {
    throw 'hello';
  } catch (err) {
    console.log(err); // hello
  }
  // `err` block scoped. Does not exist outside the catch block.
  console.log(err); // throws `err` is not defined.
}
foo();

Since the catch parameter overrides variables with the same name in the current execution context—enclosing function or global context—any initializer for the catch parameter does not affect those variables.

function foo() {
  let err = 0;
  try {
    throw 'hello';
  } catch (err) {
    console.log(err);
    err = 10;
  }
  console.log(err);
}

foo();

Of course, if we declare a block scope variable same as catch parameter inside the catch block, then Js will complain.

function foo() {
  try {
    throw 'hello';
  } catch (err) {
    console.log(err);
    let err = 2; // will throw an error.
  }
  console.log(err);
}

Declarations with var are not block-scoped and hoisted to the top of the function. Also, JavaScript is more forgiving towards re-declaration of variables with var. That’s why no error is raised even in the ‘strict’ mode.

function foo() {
  'use strict';
  err = 1;
  try {
    throw 'hello';
  } catch (err) {
    console.log(err); // hello
    var err = 2;
  }
  console.log(err); // 1
}
foo();

Hitesh

Hi, I am Hitesh.

|