I wasted several hours debugging a problem last night in some JavaScript code, and now that (I think) I've got it sorted out, it's time to share the pain. The issue stemmed from my misunderstanding of how variable scoping works in JavaScript. The MDN docs on the var statement helped clear things up, but here's a few examples to demonstrate the problem.

## Example 1

Let's declare a variable `i` that's set to `5`, then call a function that defines another `i` as part of a `for` loop. Unsurprisingly, the inner loop prints out 1 through 9, while the first and last statements prints 5 (the value of the original `i` variable).

``````function counter() {
for (var i = 0; i < 10; i++) {
document.writeln(i);
}
}

var i = 5;
document.writeln(i + '<br>');    // 5

counter();                       // 0-9 (counter sets i to 0)

document.writeln('<br>' + i);    // 5

// output:
// 5
// 0 1 2 3 4 5 6 7 8 9
// 5
``````

No surprises so far. That did exactly what I'd expect it to do. But what if we leave the `var` keyword out of the declaration of `i` in the loop? My assumption was that it'd behave the same way... oops.

``````function counter() {
for (i = 0; i < 10; i++) {
document.writeln(i);
}
}

var i = 5;
document.writeln(i + '<br>');    // 5

counter();                       // 0-9 (counter sets i to 0)

document.writeln('<br>' + i);    // 5 ?

// output:
// 5
// 0 1 2 3 4 5 6 7 8 9
// 10
``````

So what happened the second time around? The `i` inside of `counter()` was not redeclared (no `var` this time), so it re-used the same `i` declared outside of the function, which is a global variable.

The scope of a variable declared with `var` is its current execution context, which is either the enclosing function (our first example) or, for variables declared outside any function, global (our second example).

## Example 2

Here's another example, where `i` is declared outside of a loop, and then again inside the loop. So, after reading the above, I'd consider these 2 separate `i` variables to be within different contexts. That'd be consistent with other languages.

``````var i = 5;
for (var i = 0; i <= 9; i++) {
document.writeln(i);
}
document.writeln('<br>' + i + '<br>');

// output:
// 0 1 2 3 4 5 6 7 8 9
// 10
``````

Wrong again, apparently.

True to the docs, the different context seems to only occur at the function level. If we move the `for` loop inside a function and call that, then the two `i` variables are indeed treated differently. Leave out the `var` keyword on the loop, however, and we'll end up with the same result as the second example in the last section.

``````var i = 5;

function loopFunc() {
for (var i = 0; i <= 9; i++) {
document.writeln(i);
}
}

loopFunc();
document.writeln('<br>' + i + '<br>');

// output:
// 0 1 2 3 4 5 6 7 8 9
// 5
``````

## Now With 200% More Solutions!

Update: After writing this up and lamenting on Twitter, I got two great responses with two great solutions.

### Let

First, Dave Johnson told me about the `let` keyword, which creates a new binding for the variable on every iteration, and separate from any other variable of the same name outside the loop.

So if you retry the first example in the previous section, substituting `let` for `var`, the answer is more inline with what you might expect in other languages.

``````var i = 5;
for (let i = 0; i <= 9; i++) {
document.writeln(i);
}
document.writeln('<br>' + i + '<br>');

// output:
// 0 1 2 3 4 5 6 7 8 9
// 5
``````

Read more: Exploring ES6 - `let` and `const` in loop heads

### Use Strict

A little while later, Axel Rauschmayer (author of the above article, which is part of a book) told me about strict mode, which causes an error to be thrown if a variable is not declared. It solves a slightly different problem.

The previous example would still produce the same result, but whereas we could completely forego declaring `i` and it'll simply be created as a global variable for us, if we specify "use strict" then it'll throw an error instead!

``````"use strict";

try {
for (i = 0; i <= 9; i++) {
document.writeln(i);
}
document.writeln('<br>' + i + '<br>');
}
catch (err) {
document.writeln(err);
}

// output:
// ReferenceError: i is not defined
``````

## What'd I Learn?

Um, always read the docs? Heh.

JavaScript is quite a dynamic language, and full of surprises. I'd expect one of two things instead of what actually occurred:

• The `var` keyword is optional, and omitting it still creates a separate `i` variable in its own scope.
• The `var` keyword is required, and omitting it throws a syntax error.

What we actually get is that by omitting the `var` keyword, it simply looks outside of the function for any identically named variable that was declared before the function was called, and uses that instead. We don't even have to mark the outer variable as `global` - it simply is.

My actual problem was more complex, involving recursion... actually, I haven't exactly figured out why the problem was occurring where it was, but the solution was the same.

I had a function that used `i` inside a loop without ever declaring it with `var`, and the loop called the same function again. Even though `i` was declared nowhere else in my script, somehow it led to the function being called recursively forever. Once I introduced the `var` keyword, everything worked as expected and the function stopped being called recursively as soon as the condition that should stop it was true.

JavaScript. sigh...