2

What am I missing here? This behaves as expected:

var x = 1;
(function(){
   // x === 1
})();

But,

var x = 1;
(function(){
   var x = x;
   // x is undefined
})();

I would think that x should be 1. It seems as though the var x = x nukes the value of x before it is assigned. Is this a bug? This doesn't seem very intuitive.

Was this behavior changed? I remember doing something like this in the past.

For reference:

var x = 1;
(function(){
    var y = x;
    // y === 1
})();

And:

var x = 1;
(function(){
    x = x;
    // x === 1
})();
Community
  • 1
  • 1
Michael Lewis
  • 4,252
  • 6
  • 28
  • 39
  • Typically wherever the var is declared it's as if it was declared at the very beginning of the function (before any assignments). – coyotte508 Jun 05 '16 at 19:15

5 Answers5

4
var x = 1;
(function(){
   var x = x;
})();

After variable hoisting becomes:

var x = 1;
(function(){
   var x;
   x = x;
})();
Matthew Mcveigh
  • 5,695
  • 22
  • 22
  • What about [this](https://jsfiddle.net/4w23a967/)? If your explanation is true, the linked fiddle should work, while it doesn't. – nicael Jun 05 '16 at 19:20
  • 1
    @nicael both the var declarations are hoisted above the assignments – Matthew Mcveigh Jun 05 '16 at 19:22
  • Ok, you should probably explain it also. – nicael Jun 05 '16 at 19:23
  • Then why would [this](http://stackoverflow.com/questions/6439579/what-does-var-foo-foo-assign-a-variable-or-an-empty-object-to-that-va?lq=1) work? I've seen this done before, and there are several questions on SO about the same `var x = x || {}` pattern. Did they change this behavior at some point? – Michael Lewis Jun 05 '16 at 19:31
  • 2
    @MikeLewis because this is the beginning of a file, not a function. If in the browser you include several javascript files then they are executed one after the other and if the variable was declared locally before then the new **local** declaration will be ignored but the assignment will be kept. – coyotte508 Jun 05 '16 at 19:33
2

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/var

Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it's declared. This behavior is called "hoisting", as it appears that the variable declaration is moved to the top of the function or global code.

That's why sometimes in plugins you see code like

var i,j,abc, d;

//code

In you example, the code is transformed like this:

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

The example with function arguments is different, you just change the function argument itself and the var declaration is ignored.

If a scoped variable is declared with let, it will only move up to the beginning of that scope and not of the function, so this code works:

var x = 1;
(function(){
   var y = x;
   {
        let x = y;
        console.log(x);
   }
})();

As pointed out, it's a new feature, so not supported everywhere.

And finally, here:

var x = 1;
(function(){
    x = x;
    // x === 1
})();

You do not declare x locally, so if you edit it, it'll also edit it at global scope.

coyotte508
  • 9,175
  • 6
  • 44
  • 63
1

In JavaScript all variables declared in global scope or in scope of whole function where it declared. Consider example:

var x = 1;

function f()
{
    console.log(x);
    if (true) {
        var x;
    }
}

f();

This is weird programming language design but this code also prints "undefined" because of this rule.

Dmitry Poroh
  • 3,705
  • 20
  • 34
-1

Everytime you type var you are reassigning a new variable. When you just reference x inside the function it looks up to the assignment statement above.

function f(){
    var x = x;  //this tries to reassign var x to undefined.
}
MARyan87
  • 1,656
  • 2
  • 12
  • 15
-2

what you are doing here is setting x as a global variable and then setting it to reference itself, overwriting the 1, making x => x which would be undefined.

Johnathan Ralls
  • 131
  • 1
  • 12