1

console.log(i);
    for(var i=0;i<2;i++){
          console.log(i);
    }

This shows some unexpected output in browser. Can anyone please explain this? The output is:

Output

Its actually quite different on different console's. The mozilla documentation says this:

// myVarVariable is visible out here

for (var myVarVariable = 0; myVarVariable < 5; myVarVariable++) {
// myVarVariable is visible to the whole function }

// myVarVariable is visible out here

vsemozhebuty
  • 12,992
  • 1
  • 26
  • 26
Raghav
  • 77
  • 8
  • 4
    What exactly is the "unexpected" part? – Pointy Feb 01 '19 at 16:20
  • 1
    What is the question? It seems to be behaving exactly as I expect - you get `undefined` logged, then `0` then `1`. What *should* happen instead? – VLAZ Feb 01 '19 at 16:21
  • 2
    Possible duplicate of [JavaScript loop variable scope](https://stackoverflow.com/questions/18465211/javascript-loop-variable-scope) - Hmm. This may actually be dated. `let` seems to counter this answer, but for the current implementation OP is using, it stands true. – Tyler Roper Feb 01 '19 at 16:21
  • @TylerRoper that's true and probably answers OP's question...but I'm confused what the question even is. The quote from the Mozilla documentation (MDN?) also shows the same, albeit not in as much depth. I don't know what OP's confusion even is here. – VLAZ Feb 01 '19 at 16:23
  • @VLAZ According to mozilla documentation, the variables declared with var are available out of block. But, here is it not working. Check it out here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript – Raghav Feb 01 '19 at 16:26
  • 1
    @RaghavMaheshwari `i` **is available** before the `for` loop. The *value assignment* isn't. The documentation is correct - it covers the visibility of the *variable*, not assignments. – VLAZ Feb 01 '19 at 16:27
  • @VLAZ Yeah, Correct! My Bad! Thank you. – Raghav Feb 01 '19 at 16:29
  • @VLAZ Hey, Again it seems to be an issue, if i try the same code in https://jsconsole.com/. It shows 2 0 1 as outputs. Is it like after the loop is done, it updates it there? – Raghav Feb 01 '19 at 16:31
  • 1
    I get `undefined`, `1`, `0`. I copy pasted your entire snippet from here as a single code that was run. – VLAZ Feb 01 '19 at 16:33
  • I get undefined, 0, 1, as in your example (and according to the spec) - I assume @VLAZ did too and just mistyped the order of the 0 and 1 – Robin Zigmond Feb 01 '19 at 16:34
  • 1
    @RobinZigmond yeah typo when posting the comment here. [screenshot of result](https://i.imgur.com/5wGRfhO.png) – VLAZ Feb 01 '19 at 16:35
  • @VLAZ I have no clue, how does it differ in https://jsconsole.com/ then. That's realy strange. Thanks anyways – Raghav Feb 01 '19 at 16:35
  • Wait, I just realised something - if you run this code *twice* there, you'd get `2` -> `0` -> `1` because you'd retain the value of `i` from the end of the previous loop. – VLAZ Feb 01 '19 at 16:37
  • Yeah, actually, got that. My Bad – Raghav Feb 01 '19 at 16:40

5 Answers5

2

This is due to hoisting. In javascript the variable declared with var shows hoisting. Hoisting is process in which all the declarations of variables are brought to the top of of the scope on java script. But note they are not assigned the value which is assigned below in code. let and const doesnot show this behaviour

console.log(x);
var x = 4;
console.log(y)
let y = 4
Maheer Ali
  • 35,834
  • 5
  • 42
  • 73
2

There's nothing unexpected in your code, it is behaving as it should.

console.log(i);

This log statement prints undefined because of a concept known as hoisting in javascript. When you define variables using var keyword, they are moved/hoisted to the top of the functional/local scope when javascript runs.

Now you might ask that if variable declaration is moved/hoisted to the top of the functional/local scope then why does logging i prints undefined? That's because only variable declarations are hoisted to the top, not the value of the variable. So when you log i before the loop, it gives you undefined because Javascript recognizes that variable i exists in this scope but isn't given a value yet.

Inside for loop is where variable i is initialized to value 0 and then loop executes twice and gives you 0 and 1.

Now you can also access variable i after the for loop and that is because of functional scope of var. What this means is that variables defined with keyword var are available globally if not defined in any function.

If you don't want this behavior, use let instead of var. let keyword provides block level scope which means that variables defined using let keyword are only available in the block (between curly braces) in which they are defined.

Yousaf
  • 27,861
  • 6
  • 44
  • 69
1

Declare the variable as let and that won't happen. Also check this

Vencovsky
  • 28,550
  • 17
  • 109
  • 176
  • That's fine but the code doesn't go in sync with the official documentation on mozilla website. – Raghav Feb 01 '19 at 16:24
  • 2
    @RaghavMaheshwari how is it not in sync? The behaviour is as per the documentation you quoted - the first `console.log(i)` works because `i` is visible there which the documentation also says. – VLAZ Feb 01 '19 at 16:25
  • @RaghavMaheshwari Mozilla does not own any "official" documentation as they are not owners of the standards. Ecma International owns the EcmaScript/JavaScript standards and the W3C owns other Web standards. While not true in this case, it is entirely possible for them to have incorrect information on their website. – skyline3000 Feb 01 '19 at 16:34
  • @DavidCrane you'd get hoisting even if you copy/paste the code block into the console (as opposed to pasting line by line). It's not only in the scope of functions. Moreover, it works in the global scope, which is why we'd be able to use a lot of stuff to begin with, thanks to hoisting function declarations. – VLAZ Feb 01 '19 at 16:40
  • @skyline3000 the website in question is MDN - the Mozilla Developers Network. It's not actually the property of Mozilla, it's a public wiki. The information there is regarded as very high quality and around SO is accepted on-par with official documentation. And no - the information in this instance is not wrong - the part quoted in the OP is very precisely correct. It's misunderstanding what it *means*. OP seems to expect a line of `var i = 0` to *set `i`* to zero and you to see this value before reaching that line. The docs never claim this is the case. – VLAZ Feb 01 '19 at 16:44
1

Due to variable hoisting, var declarations are physically moved to the top of their execution context's scope (in this case the global scope). Thus, your code is the same as:

var i;
console.log(i);
for(i=0;i<2;i++){
    console.log(i);
}
skyline3000
  • 7,639
  • 2
  • 24
  • 33
0

In javascript inside loops use ler in place of var... then you can even use same name for variable and receive different results. Example below:

var x = 1;
  if (true) {
    var x = 2;  // same variable
    console.log(x);  // 2
   }
   console.log(x);  // 2
   }

    function letTest() {
    let x = 1;
    if (true) {
      let x = 2;  // different variable
      console.log(x);  // 2
    }
    console.log(x);  // 1
   }