Proxy


$.proxy(function, proxy[, argument, ..., argument])
$.proxy(proxy, property[, argument, ..., argument])
// return new function whose context is set to the proxy object

It is a shorthand method of setting the context for a closure. What it ultimately does is it ensure that the value of this in a function will be the value you desire. It takes a function and context(which is nothing else than an object) and links the function by invoking .call()or .apply() and return that new function.

We could of course use the plain JavaScript .bind()method. At its core, the .proxy()method is basically an easy way to use JavaScript's apply()-based context-binding. Using $.proxy ensures that the function we passed in is actually a function, and that a unique ID is passed to that function.

This method is most useful for attaching event handlers to an element where the context is pointing back to a different object. Additionally, jQuery makes sure that even if you bind the function returned from jQuery.proxy() it will still unbind the correct function if passed the original.

$(document).ready(function() {
      var evntHandlers = {
            myName : 'Homer Simpson',

            clickHandler : function( ) {
              console.log('Hello, ' + this.myName);
          }
      };

      $("a").on('click', $.proxy(evntHandlers.clickHandler,  evntHandlers));
});
// Sample 01  
// incorrect way
  $('#myElement').click(function() {
      setTimeout(function() {
            // Problem! In this function "this" is not our element!
          $(this).addClass('aNewClass');
      }, 1000);
  });

  // correct way

  $('#myElement').click(function() {
     // give $.proxy our function,
      setTimeout($.proxy(function() {
          $(this).addClass('aNewClass');  // Now "this" is again our element
      }, this), 1000);
     // and tell it that we want our DOM element to be the
     // value of "this" in the function
  });
// Sample 02 - Using variable Closure to replace proxy
var foo = {
    makeRequest: function () {
        $.get('/foo', $.proxy(function (result) {
                this.update(result);
            }, this)
        );
    },

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

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

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

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

foo.makeRequest();
// sample - 03

// This is just a manufactured example of a situation where it might be useful. Assuming there is a 
// Person object which has a property name. It is also linked to a text input element, and whenever 
// the input value changes, the name in this person object gets updated too.

function Person(el) {
    this.name = '';

    $(el).change(function(event) {
        // Want to update this.name of the Person object,
        // but can't because this here refers to the element
        // that triggered the change event.
    });
}

// solution - 1
// One solution that we often use is to store the this context in a variable 
// and use that inside the callback function such as:
function Person(el) {
    this.name = '';

    var self = this; // store reference to this

    $(el).change(function(event) {
        self.name = this.value; // captures self in a closure
    });
}

// solution - 2
// Alternatively, we could have used jQuery.proxy here so the reference 
// to this refers to the object of Person instead of the element that triggered the event.

function Person(el) {
    this.name = '';

    $(el).change(jQuery.proxy(function(event) {
        this.name = event.target.value;
    }, this));
}
// Note that this feature has been standardized into ECMAScript 5 which now includes the bind method 
// borrowed from prototypejs and is already available on some browsers.

function Person(el) {
    this.name = '';

    $(el).change(function(event) {
        this.name = event.target.value;
    }.bind(this)); // we're binding the function to the object of person
}

Difference between $.proxy, bind, call, apply

We've got three styles of calling a function here. They are all ways of addressing the problem of context, i.e. that the this keyword will have a different value depending on how the function is called.

Aliasing

var self = this;    
setTimeout(function(){
  console.log(self);
}, 5000);

This is a very simple way. It simply sets a new variable that won't be overridden within the function. The value is closed in, so when the function is called after the timeout, self will be what you expect.

Binding

setTimeout($.proxy(function(){
  console.log(this);
}, this), 5000);

setTimeout((function(){
  console.log(this);
}).bind(this), 5000);

These two functions have identical results. This is because $.proxy does exactly the same thing as bind. bind, however, is a new syntax that isn't supported by some older browsers.

This works by permanently "binding" a context to a function. This means that, however the function is called, the value of this will always be the value of the first argument to bind.
call\/apply

setTimeout((function(){
  console.log(this);
}).call(this), 5000);

setTimeout((function(){
  console.log(this);
}).apply(this), 5000);

Again, these two functions are identical. The only difference between call and apply is what other parameters are sent to a function. call expects a list (e.g. fn.call(context, param1, param2)) whereas apply expects an array (fn.apply(context, [param1, param2])).

What both these functions do is call the function with a particular context specified.

However, neither of these functions does what you want. They both call the function immediately with a certain context, rather than waiting 5 seconds to do so. That's because call and apply work just like (): the code is executed immediately.

Conclusion

Which method is more suitable will depend on your task. For simple operations, aliasing might well do the job. But it's worth remembering that that introduces another variable, and that the context can't be set at call-time. The other methods also have their strengths in different situations, particularly when writing a library where users are supplying callback functions.

Reference

results matching ""

    No results matching ""