jQuery API

jQuery.proxy()

jQuery.proxy( function, context ) Returns: Function

Description: Takes a function and returns a new one that will always have a particular context.

  • version added: 1.4jQuery.proxy( function, context )

    functionThe function whose context will be changed.

    contextThe object to which the context (this) of the function should be set.

  • version added: 1.4jQuery.proxy( context, name )

    contextThe object to which the context of the function should be set.

    nameThe name of the function whose context will be changed (should be a property of the context object).

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.

Be aware, however, that jQuery's event binding subsystem assigns a unique id to each event handling function in order to track it when it is used to specify the function to be unbound. The function represented by jQuery.proxy() is seen as a single function by the event subsystem, even when it is used to bind different contexts. To avoid unbinding the wrong handler, use a unique event namespace for binding and unbinding (e.g., "click.myproxy1") rather than specifying the proxied function during unbinding.

Examples:

Example: Change the context of functions bound to a click handler using the "function, context" signature. Unbind the first handler after first click.

<!DOCTYPE html>
<html>
<head>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
  
<p><button type="button" id="test">Test</button></p>
<div id="log"></div>

<script>
var me = {
  type: "zombie",
  test: function(event) {
    // Without proxy, `this` would refer to the event target
    // use event.target to reference that element.
    var element = event.target;
    $(element).css("background-color", "red");

    // With proxy, `this` refers to the me object encapsulating
    // this function.
    $("#log").append( "Hello " + this.type + "<br>" );
    $("#test").unbind("click", this.test);
  }
};

var you = {
  type: "person",
  test: function(event) {
    $("#log").append( this.type + " " );
  }
};

// execute you.test() in the context of the `you` object
// no matter where it is called
// i.e. the `this` keyword will refer to `you`
var youClick = $.proxy( you.test, you );


// attach click handlers to #test
$("#test")
  // this === "zombie"; handler unbound after first click
  .click( $.proxy( me.test, me ) )
  // this === "person"
  .click( youClick )
  // this === "zombie"
  .click( $.proxy( you.test, me ) )
  // this === "<button> element"
  .click( you.test );
</script>

</body>
</html>

Demo:

Example: Enforce the context of the function using the "context, function name" signature. Unbind the handler after first click.

<!DOCTYPE html>
<html>
<head>
  <script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
  
  <p><button id="test">Test</button></p>
  <p id="log"></p>

<script>
  var obj = {
    name: "John",
    test: function() {
      $("#log").append( this.name );
      $("#test").unbind("click", obj.test);
    }
  };

  $("#test").click( jQuery.proxy( obj, "test" ) );
</script>

</body>
</html>

Demo:

Support and Contributions

Need help with jQuery.proxy() or have a question about it? Visit the jQuery Forum or the #jquery channel on irc.freenode.net.

Think you've discovered a jQuery bug related to jQuery.proxy()? Report it to the jQuery core team.

Found a problem with this documentation? Report it on the GitHub issue tracker

  • http://rnikitin.ru Roman Nikitin

    Is it possible to send “sender” to the function?
    Something like:
    $(‘#test’).click($.proxy(obj, function(e, sender)
    {
    // sender points to $(‘#test’) current element in queue
    });

    • RomaReplier

      When the function gets called, I believe the current element in the queue is accessible via “this” from within the function. You can also get a wealth of information using the “event” object which is also passed to that function.

      • Trevor

        If you’re changing the this object with $.proxy, the original this object that would normally be passed is presumably lost.

      • http://rnikitin.ru Roman Nikitin

        No, it’s wrong.
        Example:
        we have js class
        var A = function() {};
        A.prototype =
        {
        init: function()
        {}
        clicked: function(e, sender){}
        }

        So, without proxy init would be:
        init: function()
        {
        var me = this;
        $(‘.test’).click(function(e)
        {
        me.clicked(e, this);
        });
        }

        with proxy we can use it:
        init: function()
        {
        var me = this;
        $(‘.test’).click($.proxy(this.clicked));
        }

        But we didn’t get a point to sender.
        We can use $(‘.test’), but it may content more then 1 sequence.
        So, the idea is to pass sender as extra argument to proxy function.

        • http://jimmycuadra.com/ Jimmy Cuadra

          You can access the original DOM element from the currentTarget property of the event object that is passed to your function. See my post: http://www.jimmycuadra.com/blog/16-understanding-jquery-1-4-s-proxy-method

          • http://rnikitin.ru Roman Nikitin

            Thanks a lot!
            A thinked that we should use e.target, but sometimes it points to child element.
            And after your post I found the e.currentTarget property that totally solve this problem.

  • http://www.cgartworld.com/ William K

    This should be extended so you can also pass in extra arguments to the function (which will get appended to the existing arguments)

    • Celtric

      Something like $(“#test”).click( jQuery.proxy( obj, “test”, [arg1, arg2, ...] ) ); being equivalent to obj.test(arg1, arg2, …);

      • Anonymous

        I agree, this method seems like an attempt to emulate the same type of functionality you get from Prototype’s Function.Bind method. This type of utility is nice to have, but I definitely agree that it is not complete without the ability to pass arguments as well. If they don’t get to it, i’ll probably write a script to overload this method myself and share it here.

      • http://blog.petersendidit.com/ David Petersen

        You can already do that just need to use bind.

        $(“#test”).bind(‘click’,{arg1:’foo’,arg2:’bar’},jQuery.proxy( obj, “test” ));

  • azoff

    In case anyone is interested, I added the ability to pass extra arguments (currying) to jQuery.proxy by means of an extension. You can grab the file here (production | development) and read more about it here. The function signature is exactly the same but I overloaded it to accept any arguments (less the first two) as the arguments to pass to the bound function.

    • Anonymous

      Awesome, thanks; without the pseudo-currying “proxy” is really only a half-solution.

      [edit] whoa – actually I’m seeing that if I add in your “proxy” version then lots of stuff quits working; it’s hard to tell exactly what through the fog of minification … I see the errors however even if my own code never calls “$.proxy()”.

  • http://prestaul.myopenid.com/ Prestaul

    Your event handlers will be called with the same arguments that they’ve always been called with. All that .proxy() gives you is the ability to set the execution context (the “this”) of those callbacks. To get the element that triggered the event you’ll use event.currentTarget.

    function Foo() {
    $(‘button’).click($.proxy(this.handleClick, this));
    }
    Foo.prototype = {
    handleClick: function(event) {
    assert(this instanceof Foo); // true
    assert(event.currentTarget.is(‘button’)); // true
    }
    };

  • http://aino.se/ David

    How about adding arguments like this:

    proxy = function( fn, scope ) {
    return function() {
    return fn.apply( ( scope || window ), Array.prototype.slice.call( arguments ) );
    };
    },

  • Anonymous

    I am a bit perplexed why this function was not designed to take ‘context’ consistently as the first argument. It will avoid any confusion and be more object oriented like if it was:

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

    • http://twitter.com/jethrolarson Jethro Larson

      That would also be consistent with .call() and .apply() where context is the first param. That would make the syntax easier to remember.

      • http://jimmycuadra.com/ Jimmy Cuadra

        I agree. It will also make it consistent with Function.prototype.bind, which $.proxy is a rough equivalent for, and which will ultimately replace $.proxy when it becomes part of JavaScript itself with the implementation of ECMAScript 5.

    • lanxiazhi

      The two methods are the same. Why not delete the second one ?
      We can choose to ignore the second one.

    • Dnnbuddy

      One of the most required functions for us. Refer the following link for understanding a real life application of $.proxy.

      http://dnnbuddy.wordpress.com/2010/06/14/attach-event-handlers-while-context-is-pointing-back-to-a-different-object/

  • Anonymous

    It’s not clear from the description that the new method will always get the current dom event passed in as the first argument. To me $.proxy isn’t really a good name in that case. $.domEventProxy may be better. $.proxy is too generic.

  • Gillish

    The sad thing about this proxy method is that you cant use comparisation anymore.

    var a = function(){};
    var b = a;

    a == b //true

    var a = function(){};
    var b = $.proxy(a);
    var c = $.proxy(a);

    b == c // false probably caused by the unique uuid

  • Christian

    Here is an example where the 2 syntaxes are useful within the same function:

    function CSV(){}

    CSV.prototype.create = function( rows ){
    return $.map( rows, $.proxy( function( row ){
    return $.map( row, $.proxy( this, 'quote' ) ).join(“,”) + “n”;
    }, this )).join('');
    };
    CSV.prototype.quote = function( text ){
    return '”' + String( text ).replace(new RegExp('”','g'), '”"') + '”';
    };

    var rows = [
    ['title','year','rating'],
    ['a','2005','5'],
    ['b','2006','4']
    ];

    var csv = new CSV();

    csv.create( rows );

  • Zonekiller

    “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.”

    But what if you don’t want to unbind? Can this be made optional in later release?

  • Felipe alcacibar

    i port from MochiKit a function that do the same of proxy but with params the plugin is there
    http://www.chileweb.cl/~counter/jquery-plugins/js/jquery/jquery.func.js

  • wizzud

    Note that the first option – jQuery.proxy(function, context) – only works when context is a pure object. For example…

    var obj = function(opts){ obj.init(opts); }
    $.extend(obj,
    { version: 1
    , init: function(opts){
    this.name = (opts || {}).name || 'John';
    }
    , test: function() {
    alert( this.name );
    $(“#test”).unbind(“click”, obj.test);
    }
    } );
    obj({name: 'Fred'});

    // Note that this is the *second* method – jQuery.proxy(context, name) – and works :
    $(“#test”).click( jQuery.proxy( obj, “test” ) );

    // Using the *first* method – jQuery.proxy(function, context) – does NOT work :
    // $(“#test”).click( jQuery.proxy( obj.test, obj ) );

    This is because in the first method $.proxy tests context to be NOT a function – which fails here because the context (obj) IS a function … but obj should still be valid for use as context!

    Note: this DOES work :
    $(“#test”).click( jQuery.proxy( obj.test, null, obj ) );

    This is because jQuery.proxy actually has 3 arguments, but the API only instructs for the use of the first 2. The proxy function tests for just those first 2 arguments being supplied, and manipulates them out to its own 3. So, supplying all 3 – with the 2nd one as false(ish) – will bypass proxy's checks … effectively jQuery.proxy(function, null, context).

    And before anybody jumps in with “Well just use the second method then”, that would be fine for the example above, but what if the function isn't a method of obj? What if it needs to be an anonymous function, or one built at runtime? For example, this won't work :
    // $('#test').click( jQuery.proxy( function(){ alert(this.version); return false; }, obj ) );

  • wizzud

    Note that the first option – jQuery.proxy(function, context) – only works when context is a pure object. For example…

    var obj = function(opts){ obj.init(opts); }
    $.extend(obj,
    { version: 1
    , init: function(opts){
    this.name = (opts || {}).name || 'John';
    }
    , test: function() {
    alert( this.name );
    $(“#test”).unbind(“click”, obj.test);
    }
    } );
    obj({name: 'Fred'});

    // Note that this is the *second* method – jQuery.proxy(context, name) – and works :
    $(“#test”).click( jQuery.proxy( obj, “test” ) );

    // Using the *first* method – jQuery.proxy(function, context) – does NOT work :
    // $(“#test”).click( jQuery.proxy( obj.test, obj ) );

    This is because in the first method $.proxy tests context to be NOT a function – which fails here because the context (obj) IS a function … but obj should still be valid for use as context!

    Note: this DOES work :
    $(“#test”).click( jQuery.proxy( obj.test, null, obj ) );

    This is because jQuery.proxy actually has 3 arguments, but the API only instructs for the use of the first 2. The proxy function tests for just those first 2 arguments being supplied, and manipulates them out to its own 3. So, supplying all 3 – with the 2nd one as false(ish) – will bypass proxy's checks … effectively jQuery.proxy(function, null, context).

    And before anybody jumps in with “Well just use the second method then”, that would be fine for the example above, but what if the function isn't a method of obj? What if it needs to be an anonymous function, or one built at runtime? For example, this won't work :
    // $('#test').click( jQuery.proxy( function(){ alert(this.version); return false; }, obj ) );