0

I thought declaring something with "var" made it local to its scope. Why, then, does this code seem to have not two distinct variables named "len", but just one?

for (var i=0, len=3; i<len; i++) {
    for (var j=0, len=1; j<len; j++) {
        console.log('i=' + i + ', j=' + j + ', len=' + len);
    }
}

In the output, instead of three lines, I get only one. Why?

(True on Chrome and Safari, haven't checked others.)

  • 3
    `for` does not create a new scope, so `len` is the same. – crackmigg Mar 07 '16 at 18:17
  • Thanks. So Javascript is like C, rather than like C++ in that regard. – Theodore Sternberg Mar 07 '16 at 18:20
  • 1
    @TheodoreSternberg C and C++ use the same scope rules as each other. Javascript looks like C/C++ but the scope does not behave like either of them unless you declare your variables with [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let). – Mike Cluck Mar 07 '16 at 18:22

3 Answers3

4

Because variables declared with varare bound to the function scope, not the block scope like in many other languages. For example, this works just fine:

if (true) {
  var thing = 'something';
}
console.log(thing); // 'something'

However, this will not work because the scope is defined by the function.

function a() {
  var thing = 'something';
}
function b() {
  console.log(thing); // ReferenceError
}
a();
b();
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91
2

I thought declaring something with "var" made it local to its scope.

It does: Function scope (or global scope if you use it globally). Unlike variable declarations in many similar languages, var doesn't have block-scope. So your loop is terminating after outputting just one line because you're setting len to 1 in the initializer of the inner loop, and that's the same len as the one being used by the outer loop.

That and some other aspects of var were sufficiently troublesome that it's been fixed: In ES2015 (the latest JavaScript specification), the new let has block scope (and there's some special hand-waving around for loops), so your example would work with let:

// NOTE: Only works on browsers supporting `let`!
"use strict"; // (Some browsers don't support let outside of strict mode yet)
for (let i = 0, len = 3; i < len; i++) {
  for (let j = 0, len = 1; j < len; j++) {
    console.log('i=' + i + ', j=' + j + ', len=' + len);
  }
}

But I wouldn't recommend using two nested lens like that. Even though JavaScript won't get confused, there's no guarantee the programmer coming after you won't.

let is one of the several really good things about ES2015. In all but a very few edge cases, let is the new var. Of course, until all of your target browsers have updated their JavaScript engines, you have to either stick with var or transpile.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

You are right to think that declaring something as var makes it local to the scope. That is why when you do the comparison in the inner for loop, the value of len that is used is the one that was declared in the inner loop. Hence only one line of output.