Javascript Closures

[Permalink]     blog code javascript

Today I found myself struggling needlessly with some code that generates a set of buttons on a form based on a set of callbacks that get passed in.

Basically, you pass in something that looks like this:

{
    "Save": function() {
        alert("Saving");
    },
    "Cancel": function() {
        alert("Cancelling");
    }
}

and the code creates buttons with the text "Save" and "Cancel" which alert text as you'd expect.

The problem came when assigning the callbacks to the click events, I kept finding that every button did what the last button in the definition was supposed to do. This sounds like a closure issue!

My original code was something along the lines of:

function make_buttons(buttons) {
    for(var name in buttons) {
        var button = jQuery("<input />").attr("type", "text").val(name);

        button.click(function() {
            buttons[name]();
        });
    }
}

which I thought would be sufficient.

It turns out that I'm an idiot and the name var from the make_buttons function is what was getting closed over and so it would obviously retain its final value.

What was needed was:

function make_buttons(buttons) {
    for(var name in buttons) {
        var button = jQuery("<input />").attr("type", "text").val(name);

        (function() {
            var button_name = name;
            button.click(function() {
                buttons[button_name]();
            }
        })();
    }
}

Now I've had time to reflect on it, that makes much more sense because I've now created a closure that encloses the value of name in a new variable (in a new environment) called button_name.

I think this didn't occur to me because I've been so spoiled when dealing with arrays and using Array.forEach() which makes sure every iteration is wrapped up in a function.

I considered adding a forEach method to object:

Object.prototype.forEach = function(callback) {
    for(var item in this) {
        (function() {
            callback(item);
        })();
    }
};

But I felt a bit queasy ;)

  Waffle. Move along.   blog   Things I learned today   blog   Hey, at least I'm not rioting   blog   HTML5 and holidays   blog holiday   Blah, cold. Do not want.   blog   Worst.Landlord.Ever   blog   Wheeee   blog   First!!1!one!!eleven   blog