boo-urns
boo-urns

Reputation: 10376

JavaScript scope in a try block

Say I'm trying to execute this JavaScript snippet. Assume the undeclared vars and methods are declared elsewhere, above, and that something and somethingElse evaluate to boolean-true.

try {
    if(something) {
        var magicVar = -1;
    }

    if(somethingElse) {
        magicFunction(magicVar);
    }
} catch(e) {
    doSomethingWithError(e);
}

My question is: what is the scope of magicVar and is it okay to pass it into magicFunction as I've done?

Upvotes: 45

Views: 45460

Answers (6)

Marc
Marc

Reputation: 11613

Due to javascript "hoisting" (MDN description), your variable declaration code gets translated as:

function yourFunction() {
  var magicVar;
  try {
      if(something) {
          magicVar = -1;
      }

      if(somethingElse) {
          magicFunction(magicVar);
      }
  } catch(e) {
      doSomethingWithError(e);
  }

} //end of your function

"Hoisting" moves all variables declarations to the top of the function. So magicVar is available everywhere in the function, but it's undefined until you give it a value.

Your variable has function scope.

Upvotes: 6

Nikhil Kuyya
Nikhil Kuyya

Reputation: 59

I agree with variable hoisting and function hoisting, I would like to emphasis two import points.

  • Identifier Defined in Catch parameter is i.e. err/e(error) , is scoped to Catch defined block.

  • Function first hoisting. example :

        b(); // output : 3
        var b = 2;
        function b(){
         return 3;
        }
    

Upvotes: 1

DrEnter
DrEnter

Reputation: 869

Lots of other good answers about how Javascript handles this with var, but I thought I'd address the let situation...

If a variable is defined with let inside the try block, it will NOT be in scope inside the catch (or finally) block(s). It would need to be defined in the enclosing block.

For example, in the following code block, the console output will be "Outside":

let xyz = "Outside";

try {
    let xyz = "Inside";

    throw new Error("Blah");
} catch (err) {
    console.log(xyz);
}

Upvotes: 87

Peter Olson
Peter Olson

Reputation: 142921

Javascript has function scope. That means that magicvar will exist from the beginning of the function it's declared in all the way to the end of that function, even if that statement doesn't ever execute. This is called variable hoisting. The same thing happens with functions declarations, which in turn is called function hoisting.

If the variable is declared in global scope, it will be visible to everything. This is part of the reason why global variables are considered evil in Javascript.

Your example will pass undefined into magicFunction if something is false, because magicVar hasn't been assigned to anything.

While this is technically valid Javascript, it's generally considered bad style and will not pass style checkers like jsLint. Extremely unintuitive Javascript like this will execute without any error

alert(a); //alerts "undefined"
var a;

POP QUIZ: What does the following code do?

(function() {
  x = 2;
  var x;
  alert(x);
})();
alert(x);

Upvotes: 28

gdoron
gdoron

Reputation: 150253

  • In javascript only functions create a new context -closure.
  • Every definition of a variable is really a declaration of the variable at the top of its scope and an assignment at the place where the definition is.

var

  • function-scoped
  • hoist to the top of its function
  • redeclarations of the same name in the same scope are no-ops

You may want to read MDN scope cheat sheet

Due to hoisting You can even do things like this:

function bar() {
    var x = "outer";

    function foo() {
        alert(x); // {undefined} Doesn't refer to the outerscope x
        // Due the the var hoising next:        
        x = 'inner';
        var x;
        alert(x); // inner

    }
    foo();
}

bar();​

bar();​

Demo

So the foo function is converted to something like this:

function foo() {
    var x;
    alert(x); // {undefined} Doesn't refer to the outerscope x
    // Due the the var hoising next:        
    x = 'inner';
    alert(x); // inner
}​

My question is: what is the scope of magicVar and is it okay to pass it into magicFunction as I've done?

Define okay..., Yes the code is valid, but it's less readable then if the variables declarations were on the top, that's all.

Upvotes: 7

zneak
zneak

Reputation: 138051

With var, variables exist from the beginning of the function to the end of it, no matter where they are declared, or even if the statement is actually ever reached. They will, however, be undefined until they are assigned another value.

So in your case, if something is false but somethingelse is true, you will call magicFunction with its first argument being undefined.

The let keyword, created in Javascript 1.9 and available (as of today, May 3rd 2012, and as far as I know) only in Firefox, declares variables with the scoped semantics you're probably used to.

Upvotes: 1

Related Questions