2

If I want to create a jQuery function using Function.prototype.bind, i.e. to the need for a wrapping function, which this value do I supply? The following trivial example does not seem to work:

// e.g.: $.fn.outerHeight() with argument true gets height including margin

$.fn.marginBoxHeight = $.fn.outerHeight.bind($.fn, true);

$.fn was the wrong choice here for the this argument. What should it be, so that the function would have access to jQuery internal methods, if needed?

Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265
lunelson
  • 561
  • 6
  • 11
  • http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/ – null1941 Jan 23 '16 at 10:48
  • 2
    Generally in jQuery you don't reference or curry, you do something more like `$.fn.marginBoxHeight = function() { return this.outerHeight(true); }` – adeneo Jan 23 '16 at 11:05
  • Thanks @adeneo yes I know, in fact that's how I solved the problem—it's more of an academic question. I'll have to look at the source; I'm guessing the right scope might be something like `$.fn.init` or `$.fn.init.prototype` – lunelson Jan 23 '16 at 12:54
  • @lunelson In that case, the academic answer would probably be "drop jQuery, and the sooner the better". – Madara's Ghost Jan 26 '16 at 08:25
  • Not possible: `this` should be the object on which you call `marginBoxHeight`, which you don't know upfront. So, you cannot use `bind`. – trincot Sep 07 '17 at 22:23

1 Answers1

0

jQuery.proxy performs currying as follows:

QUnit.test( "jQuery.proxy", function( assert ) {

    var thisObject = { foo: "bar", method: test };

    // jQuery 1.9 improved currying with `this` object context
    fn = function() {
        assert.equal( Array.prototype.join.call( arguments, "," ), "arg1,arg2,arg3", "args passed" );
        assert.equal( this.foo, "bar", "this-object passed" );
    };
    cb = jQuery.proxy( fn, null, "arg1", "arg2" );
    cb.call( thisObject, "arg3" );
} );

QUnit.test( "jQuery.proxy", function( assert ) {
 assert.expect( 9 );

 var test2, test3, test4, fn, cb,
  test = function() {
   assert.equal( this, thisObject, "Make sure that scope is set properly." );
  },
  thisObject = { foo: "bar", method: test };

 // Make sure normal works
 test.call( thisObject );

 // Basic scoping
 jQuery.proxy( test, thisObject )();

 // Another take on it
 jQuery.proxy( thisObject, "method" )();

 // Make sure it doesn't freak out
 assert.equal( jQuery.proxy( null, thisObject ), undefined, "Make sure no function was returned." );

 // Partial application
 test2 = function( a ) {
  assert.equal( a, "pre-applied", "Ensure arguments can be pre-applied." );
 };
 jQuery.proxy( test2, null, "pre-applied" )();

 // Partial application w/ normal arguments
 test3 = function( a, b ) {
  assert.equal( b, "normal", "Ensure arguments can be pre-applied and passed as usual." );
 };
 jQuery.proxy( test3, null, "pre-applied" )( "normal" );

 // Test old syntax
 test4 = { "meth": function( a ) {
  assert.equal( a, "boom", "Ensure old syntax works." );
 } };
 jQuery.proxy( test4, "meth" )( "boom" );

 // jQuery 1.9 improved currying with `this` object
 fn = function() {
  assert.equal( Array.prototype.join.call( arguments, "," ), "arg1,arg2,arg3", "args passed" );
  assert.equal( this.foo, "bar", "this-object passed" );
 };
 cb = jQuery.proxy( fn, null, "arg1", "arg2" );
 cb.call( thisObject, "arg3" );
} );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.4.0.css">
<script src="https://code.jquery.com/qunit/qunit-2.4.0.js"></script>
<div id="qunit"></div>
<div id="qunit-fixture"></div>

The simplest example would be:

var foo = jQuery.proxy(function(){return this('html:first')}, jQuery)
console.log(foo() )
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

References

Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265