Attack of JavaScript's global scope

This week we had a bug in a server application. It only appeared once in a while, and only for some users. To the user, data appeared to be getting lost, though I could clearly see the data was there. Here is a minimalistic recreation of the bug:

// A simple constructor. Gives each object a unique id.
var nextId = 1;
var newBar = function() {
    var bar = {};   
    bar.id = nextId++;
    bar.doStuff = function(callback) {
        // Some Async process happens here, calls callback when done.
        setTimeout(callback, 1000);
    };
    return bar;
};

// Creates a new instance of `bar` and performs a task on it.
function foo() {
    bar = newBar();
    bar.doStuff(function(){
        // on finish, log the unique id of bar.
        console.log(bar.id);
    });
}

// Run the code
for(var i = 0; i < 5; i++) {
    foo();
}

Did you catch the bug in there? console log is:

5
5
5
5
5

Why? Global scope. I forgot var when bar was declared in the function foo. So instead of bar being in function scope, it was in global scope. Since it was in global scope, the value of bar got overwritten every time foo was called. Stupid.

Now to be fair, this is 100% my mistake, not JavaScripts. I know it works this way, even if it’s a poor language design choice.

I introduced this bug as the result of some refactoring. An easy mistake to make. But in a project of 20000+ lines of code, it was difficult to track down. Test cases didn’t cover this specific scenerio. The code worked fine when foo was only called once at a time.

The simple solution to avoiding these issues, which I should have done before I wrote any code, is to use strict mode.

"use strict";

When strict mode is enabled, modern JavaScript engines detect this problem and throw an error. Lesson learned; always use strict mode.

Tagged:

web-developer, programmer, development, code, programming

You can contact me on Twitter.

Recent & Popular Articles

Browse All >