$.proxy

06/06/2013, Thu
Categories: #JavaScript
Tags: #jQuery

Getting the Right 'this'

With jQuery, you often find yourself using an event listener with a callback function like so:

// Common Event Handler

$(document).ready(function () {
  $(".my-element").click(function () {
    console.log("this is ", this);
  });
});

The 'this' is the console.log() refers to javascript element, '.my-element'. There are however times when you wish to refer to another 'this', such as when you want the parent object:

// Wrong Context 'this'

$(document).ready(function () {
  var MyConstructor = function () {};

  MyConstructor.prototype = {
    init: function () {
      // logs 'doing stuff'
      this.doStuff();

      // when element is clicked, there will be an error
      // because of the wrong 'this' reference
      $(".my-element").click(function () {
        this.doStuff();
      });
    },
    doStuff: function () {
      console.log("doing stuff");
    },
  };

  MyConstructor.prototype.init();
});

An error will log in the console when clicking on the words.

Demo

The context must change in order for 'this' inside the event handler to reference the constructor's 'this'.

// Using $.proxy to Correct Context
$(document).ready(function () {
  var MyConstructor = function () {};

  MyConstructor.prototype = {
    init: function () {
      // logs 'doing stuff'
      this.doStuff();

      // the 'this' now refers to the constructor's 'this'
      $(".my-element").click(
        $.proxy(function () {
          // 'this' should work
          this.doStuff();

          // to reference back the dom object
          var _this = event.target;
        }, this)
      );
    },
    doStuff: function () {
      console.log("doing stuff");
    },
  };

  MyConstructor.prototype.init();
});

Now when the words are clicked, the console should log out 'doing stuff'.

Demo

If you wish to refer back to the original 'this' for the event handler you would need to get it from the event.

As a side note, $.proxy could have also been use another way, but the result isn't as clean:

// Another $.proxy Alternative

$(document).ready(function () {
  var MyConstructor = function () {};

  MyConstructor.prototype = {
    init: function () {
      // logs 'doing stuff'
      this.doStuff();

      // alias the prototype
      var mcp = MyConstructor.prototype;

      // another way of using proxy
      // more in line with the jQuery docs
      $(".my-element").click(function () {
        // actually a trivial example
        // could have done mcp.doStuff()
        // use to demonstrate proxy
        $.proxy(mcp.doStuff(), mcp);
      });
    },
    doStuff: function () {
      console.log("doing stuff");
    },
  };

  MyConstructor.prototype.init();
});

Demo