You don't need to use $.proxy

12 December 2011 · 5 minute read · jquery · javascript

I’ve been recently going through some extending of a jQuery UI widget which a colleague had written when I came across quite a number of statements that were using the proxy method from jQuery.

For anyone who’s not familiar with the proxy method is allows you to take a function and specify a context (the this value) so when you pass it around for execution you always know what you’re going to have as the context.

The method has been around for a while and it did serve a good purpose but these days its usefulness is becoming limited and I’m going to look at a few reasons as to why you shouldn’t be using it.

Understand this

The most common reason I see that people will use proxy is because they don’t understand how this works in JavaScript. While there are dozens of articles through your favourite search engine explaining this (here’s a good start) I’ll do my best to give a quick overview.

When people come from C# they already have a notion of this and what it represents, unfortunately this is a broken assumption when moving to JavaScript. In C# this represents the current class which you’re working within but since JavaScript isn’t a classical language there isn’t the concept of a class so you couldn’t really associate it to one could you?

Instead this represents the context for which a function is executed for and different kinds of execution result in different contexts. Here’s a few examples:

  • Invoking a function from an object will set the context to the owner object
  • Invoking a function literal will set the context to the global object (window in a browser)
  • Invoking a function with apply/ call allows it to be controlled

And this is why a lot of people get utterly confused with this in JavaScript.

But what does this have to do with the $.proxy method? As I said one of the most common reasons I see people using it is because they want to be able to access members of a particular object within a callback (such as a function called from an AJAX success). Because they are aware that in their outer function they can go this.foo they expect it to be available within the callback (after all isn’t the callback in the same class?) but it will fail so they use $.proxy to ensure that they can access the member(s) they require.

So why is it a poor choice in this scenario? Well the reason is that you can solve the problem in a much simpler fashion, by understanding JavaScript closures. You can draw a lot of similarities between JavaScript closures and C# closures, but the simplest explanation is that a variable with be within scope until all functions that require is have been descoped. But with the case of this, since it changes between function scopes the var that = this pattern emerged in JavaScript.

Let’s have a look at some code:

var foo = {
    makeRequest: function () {
        $.get('/foo', $.proxy(function (result) {
                this.update(result);
            }, this)
        );
    },

    update: function (data) { /* ... */ }
};

//somewhere later in the code
foo.makeRequest();

Here we’re using the proxy method to make it possible to access the update method, since when we called the makeRequest method its this is a reference to foo (we’re assuming that the assignment of foo is out of scope for the makeRequest method). So let’s update it to use variable closures:

var foo = {
    makeRequest: function () {
        var that = this;
        $.get('/foo',function (result) {
            that.update(result);
        });
    },

    update: function (data) { /* ... */ }
};

foo.makeRequest();

The difference here is that I’m assigning the value of this to a variable before the callback is created and inside the callback I refer back to the variable.

So why is this better than using proxy? The primary reason is readability, if you look at the first snippet you’re intention is obscured by the use of proxy to change the scope. When someone who understands JavaScript comes to that snippet they have to know what the use of proxy is and why the this context needs to be controlled. With the second snippet it’s clearer to see that you want to call the update method on the same object which makeRequest was invoked from.

Use built-in methods

An often missed note of JavaScript (well ECMAScript really) is that the functionality that is provided by proxy (and the similar methods in the other libraries) is built into the language, through the bind method. The bind method was added as part of ECMAScript 5 and

Creates a new function that, when called, itself calls this function in the context of the provided this value, with a given sequence of arguments preceding any provided when the new function was called.

Hmm that sounds pretty much like what you get from the proxy method yet it’s built into the language.

This means that you can (potentially) get a performance boost (check it out on JSPerf) by using a native browser API rather than the wrapper. Also at the time of writing jQuery (1.7.1) doesn’t use the native browser method it does the code itself.

Performance aside the main difference between the jQuery implementation and the ECMASCript 5 specification is the jQuery proxy method does not throw a type error if the first argument is not a function which the spec states bind will do. So although they are named differently they are providing the same functionality except for a critical check.

The take away from this point is that it’s built into the language so using it makes a lot of sense and when you’re in browsers that don’t support it it’s easy to polyfil the missing API (the mdn docs include the polyfil).

Conclusion

That wraps up my “rant” against using the proxy method in jQuery. The goal of this article was to teach you a bit more about the JavaScript language and that things people commonly try and work around have simpler solutions.

By understanding language concepts such as this and closures you can avoid manipulating scope.

By knowing what’s new in the language you can use built-in APIs and make faster and more portable code.


Published: 2017-07-30 20:47:37 +1000 +1000, Version: bfd8bbd