Understanding jQuery 1.4's $.proxy() method

No sooner than I wrote about how to control a JavaScript function's context with the Prototype Function.prototype.bind, jQuery 1.4 is released and one of its new tricks is jQuery.proxy, which we can use for exactly the same purpose.

To refresh you, the problem that needed solving was how to preserve a reference to the calling object when the value of this is changed. Consider the following:

MyModule = function() {
  this.$div = $('#testdiv');
  this.myString = "Hi! I'm an object property!";
  
  this.$div.click(this.handleClick);
};

MyModule.prototype.handleClick = function() {
  console.log(this.myString); // undefined
};

var m = new MyModule();

When you click on the div, we are given undefined, because this now refers to the DOM element that triggered the event and not the instance of MyModule we've stored in the variable m. The element does not have a myString property, and hence, it is undefined. So how do we access the myString we want? The solution I wrote about previously was to use Function.prototype.bind from the Prototype library, which allows us to control what this will refer to inside the function we're calling. But now in version 1.4 of jQuery, we can handle this situation with the new jQuery.proxy method. The method has two signatures:

jQuery.proxy( function, scope )
jQuery.proxy( scope, name )

In the first form, the function argument is the function we're calling, and the scope argument sets the context the function should be called in. In the second form, the scope comes first, and the name argument is a string that gives the name of the function we're calling. Note that the function provided in name should be a property of whatever object we're using as the scope. Let's look at an example to make this more clear.

MyModule = function() {
  this.$div = $('#testdiv');
  this.myString = "Hi! I'm an object property!";
  
  this.$div.click($.proxy(this.handleClick, this));
};

MyModule.prototype.handleClick = function() {
  console.log(this.myString); // Hi! I'm an object property!
};

var m = new MyModule();

Now when we click on the div, we see the result we want, because this is now bound to our m object, which is an instance of MyModule. This uses jQuery.proxy's first signature. We could achieve exactly the same effect using the second signature by using this line instead:

this.$div.click($.proxy(this, "handleClick"));

The small "gotcha" that remains is how to access the DOM element that triggered the event, now that we've changed the value of this within our function. The good news is that, like before, all event handling functions are passed an event object with details about the event that occurred. Within that event object is a property called currentTarget, which holds exactly what we're looking for: the DOM element that triggered the event. Here is an example of how to access it:

MyModule.prototype.handleClick = function(event) {
  console.log(this.myString); // Hi! I'm an object property!
  console.log(event.currentTarget); // <div id="testdiv">
};

Thanks to jQuery.proxy, we now have the ability to control function scope with jQuery alone. To read more about all the new features in jQuery 1.4, check out John Resig's overview on The 14 Days of jQuery.