Simplify Scope with Javascript Closures

Posted by Maciek Mon, 25 Sep 2006 20:25:09 GMT

For those of you using Javascript prototypes as classes and interacting them with HTML or DOM elements, it’s often tricky or painful to keep things clean and nicely separated. Often, the result is a bunch of global (i.e. members of window) variables littered all over the place. Still more difficult is the problem of somehow associating given DOM objects with given class (or prototype) instances without having to use clumsy proxies or tracking keys in hashes.. etc. You can greatly simplify this sort of code by using closures. In the following article, I will give you a simple pattern to apply to any functionality you want to attach to objects that steal or would otherwise confuse scope. This pattern is useful anywhere you attach functions to the properties of objects outside of those functions’ context: AJAX XMLHttpRequest objects, DOM elements, or your own prototype-derived objects..

The problem

In Javascript applications we often attach functions to objects in the current document. A common use is the onclick function. For example, say we define a button in the following manner:


<input type="button" value="Click me" id="mybutton" />

Now let’s say that we want to make this button change its own label when we click it. We could attach a function to the button to do so:


var myfunc = function()
{
    this.value = "I have been clicked!";
};

document.getElementById("mybutton").onclick = myfunc;

When we click the button, the Javascript interpreter will execute the attached function by looking up the function referenced by the onclick property of the button. It will use the button as the scope of execution, which means that the this keyword will be referring to the button, and not something else.

Why do I make this distinction? Well, ask yourself what might happen if I were to insert the following statement directly below the function definition, like so:


var myfunc = function()
{
    this.value = "I have been clicked!";
};

myfunc();

What does the this keyword refer to in this context? Obviously not our button, since we’ve never referenced it in any way. If you’ve put your Javascript into a script tag then this in this context typically means the Browser’s window object. When this code runs, it will run as if we had typed:


window.value = "I have been clicked!";

Thus you can see that the meaning of this changes depending on what a particular anonymous function is attached to. Context is everything in Javascript, and this can become extremely confusing if we are using instances of objects constructed from prototypes. Take the following example:


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<script type='text/javascript'>
function Bob(id_)
{
    this.id = id_;
    this.specialvalue = "_" + id_ + "_";
};

Bob.prototype.doSomething = function()
{
    return this.specialvalue;
}

Bob.prototype.hello = function()
{
    // this.value hopes "this" is a button
    // this.doSomething() hopes "this" is a Bob
    this.value = "specialvalue("+this.doSomething()+")";
};
</script>
<body>
<input type="button" value="test me" id="btn1" />
</body>
<script type="text/javascript">
var b = new Bob("abc");
document.getElementById("btn1").onclick = b.hello;
</script>
</html>

Here we have created a Javascript “class” called Bob and created an instance of it (at bottom of source). We then take the hello property of the object instance b (which happens to be a function) and make the onclick property of the button refer to it. Clearly, we intend to make the button’s value property take on the value “abc”. If you look at the hello() function in Bob’s prototype however, you can see that two scopes are about to collide and this might not work!

When we run this function, what will happen? Will instance b get a new property called value, set to to the result of doSomething()? Or perhaps will the button change its own label (the value property)? In other words, what is the meaning of the this keyword in this context?

The answer is that the Javascript interpreter will resolve this to be the button. This happens because the moment we’ve assigned the button’s onclick property to instance b’s hello property, the function hello becomes anonymous and no longer uses the scope from where it came. Hence our Javascript interpreter gives us the following message:

this.doSomething is not a function

So much for that. We need some way to preserve both contexts. In particular, we would like to simply have a reference to bob without having to resort to pesky global variables, attaching other data to the button, etc.

The Solution Pattern

Enter Javascript closures. In functional programming, we can preserve a given scope by creating a function that will be called at a future time and then “closing” some (or all) of its arguments. A basic pattern for creating closures in Javascript could be:


function createClosure(scope_)
{
    var origScope = scope_;
    var callMe = function()
    {
        origScope.somefunc();
    }
    return callMe;
}

// preserve this
someobject.someproperty = createClosure(this);

A closure is created by calling a function, storing some variables inside of that function, and returning a function that uses those variables. Javascript makes the syntax fairly simple.

Fixing The Example

We are now ready to fix our example such that we can reference instance b while also changing the value property of the button without any outside help. The distinction without any outside help is important because there are other ways to achieve what we’re doing here, however, they don’t necessarily lend themselves to more sophisticated or complex examples. We want to minimize use of ‘global’ variables as much as possible and not have to keep track of instances if we don’t absolutely need to.

In this case, we’ll preserve a reference to scope instance b while attaching the function to the button:


<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<script type='text/javascript'>
function Bob(id_)
{
    this.id = id_;
    this.specialvalue = "_" + id_ + "_";
};

Bob.prototype.doSomething = function()
{
    return this.specialvalue;
}

Bob.prototype.hello = function(scopeObj)
{
    scopeObj.value = "specialvalue("+this.doSomething()+")";
};
</script>
<body>
<input type="button" value="test me" id="btn1" />
</body>
<script type="text/javascript">
var b = new Bob("abc");

function createOnclick(scope_)
{
    var scope = scope_;
    var callMe = function()
    {
        scope.hello(this);
    };
    return callMe;
};

document.getElementById("btn1").onclick = createOnclick(b);
</script>
</html>

As you can see, this time we use our simple pattern and preserve the scope (in this case instance instance b) inside of a closure. The closure’s “closed argument” in this case is the variable scope. If we wanted, we could add arguments callMe function if we wanted some of our arguments to be open. If we did that, the resulting closure we created could take some arguments while keeping others fixed. At any rate, our button now re-labels itself to “abc” as originally intended, without any global variables or tracking procedures.

Closures present a simple yet powerful technique for simplifying complex programs as well as solutions to problems that occur in functional programming.

Posted in , ,  | Tags , , ,  | 3 comments | no trackbacks

Trackbacks: 0

Use the following link to trackback from your own site: http://schf.uc.org/articles/trackback/265

Comments: 3

Leave a response | RSS feed for this post

  1. # Marcel Popescu said about 23 hours later:

    Out of curiosity – did you even look at this article after you posted it? Not read – look.

    <input type=”text/javascript” value=”Click me” id=”mybutton”

    Do these look like normal tags to you?

    (And no, it doesn’t look any better in IE, either.)

  2. # Maciek said 20 days later:

    Fixed, thanks.

  3. # Kumar S said 23 days later:

    Great article. (Y)

Leave a response

Toggle website and email fields