SLaks.Blog

Making the world a better place, one line of code at a time

Delegates vs. Function Pointers, part 5: Javascript

Posted on Monday, July 25, 2011, at 12:33:00 AM UTC

This is part 5 in a series about state and function pointers; part 1 is here.

Last time, we saw how C# 2 supports closures by compiling anonymous functions into member functions of a special class that holds local state from the outer function. 

Unlike the languages we’ve looked at before, Javascript has had closures baked in to the languages since its inception.  My standard example can be achieved very simply in Javascript:

var x = 2;
var numbers = [ 1, 2, 3, 4 ];
var hugeNumbers = numbers.filter(function(n) { return n > x; });

This code uses the Array.filter method, new to Javascript 1.6, to create a new array with those elements from the first array that pass a callback.  The function expression passed to filter captures the x variable for use inside the callback.

This looks extremely similar to the C# 2.0 version from last time.  However. under the covers, it’s rather different.

Like .Net managed instance methods, all Javascript functions take a hidden this parameter.  However, unlike .Net, Javascript does not have delegates.  There is no (intrinsic) way to bind an object to the this parameter the way a .Net closed delegate does.  Instead, the this parameter comes from the callsite, depending on how the function was called.  Therefore, we cannot pass state in the this parameter the way we did in C#.

Instead, all Javascript function expressions capture the variable environment of the scope that they are declared in as a hidden property of the function.  Therefore, a function can reference local variables from its declaring scope.  Unlike C#, which binds functions to their parent scopes using a field in a separate delegate object that points to the function, Javascript functions have their parent scopes baked in to the functions themselves. 

Javascript doesn’t have separate delegate objects that can hold a function and a this parameter.  Instead, the value of the this parameter is determined at the call-site, depending on how the function was called.  This is a common source of confusion to inexperienced Javascript developers.

To simulate closed delegates, we can make a method that takes a function as well as a target object to call it on, and returns a new function which calls the original function with this equal to the target parameter.  That sounds overwhelmingly complicated, but it’s actually not that hard:

function createDelegate(func, target) {
    return function() { 
        return func.apply(target, arguments);
    };
}

var myObject = { name: "Target!"};
function myMethod() {
    return this.name;
}

var delegate = createDelegate(myMethod, myObject);
alert(delegate());

This createDelegate method returns a function expression that captures the func and target parameters, and calls func in the context of target.  Instead of storing the target in a property of a Delegate object (like .Net does), this code stores it in the inner function expression’s closure.

Javascript 1.8.5 provides the Function.bind method, which is equivalent to this createDelegate method, with additional capabilities as well.  In Chrome, Firefox 4, and IE9, you can write

var myObject = { name: "Target!"};
function myMethod() {
    return this.name;
}

var delegate = myMethod.bind(myObject);
alert(delegate());
For more information, see the MDN documentation.

Categories: javascript, closures, functions Tweet this post

comments powered by Disqus