8

If I do this:

var a = 0;

(function () {
    var a = a; //want to make local a = global a
    ++a;
    console.log("fn",a);
})();

console.log(a);​

The output is:

fn NaN
0

Why does a inside of the self executing function become NaN?

I know it works fine if I do:

(function () {
    var b = a;
    ++b;
    console.log("fn",b); // fn 1
})();

But if I go the way of the first version, it has the NaN issue.

Why is this happening?

Naftali
  • 144,921
  • 39
  • 244
  • 303

4 Answers4

12

var a = a; is actually var a; a = a; due to variable hoisting. This means at the time of the assignment the old a is already shadowed by the new one (which is undefined).

The easiest way to avoid issues like that is passing the value as a parameter:

(function (a) {
    ++a;
    console.log("fn",a);
})(a);

In case a is a global variable you could also use var a = window.a; like woz suggested - but since having global variables is usually a bad idea better stay with the parameters.

Community
  • 1
  • 1
ThiefMaster
  • 310,957
  • 84
  • 592
  • 636
  • So how would I make it so that my local variable and global variable are equal at the start of the local function scope? Do I need to use a temp variable? – Naftali Jul 12 '12 at 17:36
  • 1
    See my edit. You cannot use a temporary variable for this since no matter what you do, as soon as there is `var a` in your function the outer `a` is not accessible anymore. – ThiefMaster Jul 12 '12 at 17:36
  • Ooohh I forgot about parameters :-P Duuuuh. `+1` – Naftali Jul 12 '12 at 17:37
6

The a variable inside your function expression shadows the a variable declared on the outer scope.

It becomes NaN, since in the assignment:

var a = a;

The right-side a it's actually referring to the a in the local scope.

Variable declarations are done before the function actually starts to be executed, this is commonly known as 'hoisting'.

Since it's the same variable, it holds the undefined value, and when you try to add any number to this value, it becomes NaN:

console.log(undefined + 0);
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
2

In JavaScript, the current execution context (which includes things like variable scope) is established before your code begins executing.

What this means to you is that your local variable names are allocated first. Due to hoisting, labels from var statements anywhere in the function are initialized to undefined in the current execution context. (Function statements are also initialized in this step.)

Next, your code actually begins executing. The a label is already reserved in the current execution context, so var a = a; simply assigns the local a (which is undefined) to itself.

var a = window.a works because you sidestep the scope issue by accessing global scope directly. However, this doesn't work in non-browser environments (like Node) because there is no window; the global object in Node is global.

Community
  • 1
  • 1
josh3736
  • 139,160
  • 33
  • 216
  • 263
0

there is a variable hoisting in javascript, so your code during execute looks like this:

(function () {
    var a;
    a = a; //want to make local a = global a
    ++a;
    console.log("fn",a);
})();

so firstly you have local variable a as undefined and then you assign undefined to variable a

jagm
  • 576
  • 4
  • 6