Using Self-Executing Function Arguments To Override Core jQuery Methods

Posted September 13, 2010 at 10:07 AM by Ben Nadel

Tags: Javascript / DHTML

Overriding jQuery methods (or any function for that matter) is a relatively straight forward process. All you have to do is get a reference to the old method (if you need to keep it) and then override the object key (method name) using your new function. A while back, however, I was reading Eric Hynds' blog and came across what I thought was a really elegant way to do this. He was using self-executing function arguments to create a reference to the old jQuery method that he was about to override.

 
 
 
 
 
 
 
 
 
 

When you create a self-executing function block, you have the opportunity to pass in parameters as part of the function invocation:

  • (function( argA, argB ){ .... })( paramA, paramB );

In this case, we are passing in "paramA" and "paramB", which will become the arguments, "argA" and "argB," respectively. This approach has a number of benefits including cutting down on scope-chain traversal and creating reference short-hands (ex. mapping "jQuery" parameter to "$" argument). What Eric was doing, that I found so interesting, was that he was using this parameter-argument approach to create references to methods that he was going to override.

To see this in action, I created a very brief demo that overrides the core jQuery method, html(). In the following code, I am going to prepend my own string data to any given HTML before I pass it off to the original, now wrapped, html() method:

  • <!DOCTYPE html>
  • <html>
  • <head>
  • <title>Overriding Core jQuery Methods</title>
  • <script type="text/javascript" src="./jquery-1.4.2.js"></script>
  • <script type="text/javascript">
  •  
  • // Create a self-executing function block to which we are
  • // going to pass the jQuery object and a reference to the
  • // original, core method, html().
  • (function( $, oldHtmlMethod ){
  •  
  • // Override the core html method in the jQuery object.
  • $.fn.html = function(){
  •  
  • // Check to see if we have an argument (that the user
  • // is setting HTML content).
  • //
  • // NOTE: This does not take into account the fact
  • // that we can now pass a function to this method -
  • // this is just a lightweight demo.
  • if (arguments.length){
  •  
  • // Prepend our own custom HTML.
  • arguments[ 0 ] = (
  • "<strong>HTML: </strong>" +
  • arguments[ 0 ]
  • );
  •  
  • }
  •  
  • // Execute the original HTML method using the
  • // augmented arguments collection.
  • return(
  • oldHtmlMethod.apply( this, arguments )
  • );
  •  
  • };
  •  
  • })( jQuery, jQuery.fn.html );
  •  
  •  
  • // -------------------------------------------------- //
  • // -------------------------------------------------- //
  •  
  •  
  • // When the DOM is ready, run scripts.
  • $(function(){
  •  
  • // Use the HTML method which, at this point, has been
  • // overridden with a wrapper behavior.
  • $( "body" ).html( "I was appended to BODY!" );
  •  
  • });
  •  
  • </script>
  • </head>
  • <body>
  • <!-- Intentionally left blank. -->
  • </body>
  • </html>

When I run this code, the BODY of the page now contains the following content:

HTML: I was appended to BODY!

As you can see, "HTML:" was prepended to the HTML string that we passed into the html() method.

In the above code, when I defined the self-executing function block, I passed in two parameters: the jQuery library (jQuery) and a reference to the core html() method (jQuery.fn.html). These parameters then became arguments for the self-executing function invocation, which allowed for an almost quasi-implicit reference to the original html() method.

From a functional standpoint, there's absolutely no difference between using this approach and just creating a local variable reference to the original method:

  • var oldHtmlMethod = $.fn.html;

However, there's something that just feels really nice about parameter-argument mapping in this context. Perhaps I just like the fact that the reference-logic was factored out of the override-logic, creating a slightly cleaner separation of concerns.




Reader Comments

Sep 13, 2010 at 10:31 AM // reply »
3 Comments

Good idiom - it's nice how everything happens in "one line". A lot of the time, people won't make that "var oldHtmlMethod = $.fn.html;" a local variable either, ie. it will stick around in global scope, which is possibly undesirable, and something this idiom removes.


Sep 13, 2010 at 10:40 AM // reply »
11,238 Comments

@Michael,

Good point on leaving stuff in the global scope; using this parameter-argument approach will definitely help keep variables in the preferred scoping.


Sep 13, 2010 at 1:47 PM // reply »
3 Comments

Nice post. We use this technique to add in extra functionality to jQuery's $.ajax() function. The overridden success argument, for example, looks into the returned JSON object to see if a property called ERROR has been given. That way, we can pass along a localized error message directly from the server without any extra fuss - and even though the ajax request was technically "successful" we prevent the success handler from being run in the case of one of these errors.

I put up a Gist to better explain :)
http://gist.github.com/577713


Sep 13, 2010 at 1:52 PM // reply »
3 Comments

whoops, problem with that one? this should work http://gist.github.com/577722


Sep 14, 2010 at 6:40 AM // reply »
1 Comments

Nice technique, I like that :)
But why not do something like this snippet http://pastebin.com/M6wv8AwS
It create one more variable but you won't need to repeat the method name


Sep 14, 2010 at 11:22 AM // reply »
8 Comments

I believe this is considered "Aspect Oriented Programming" and Paul had a good article on how to do some cool stuff with jQuery (though he uses the much cooler term "duck punching).

Just thought I'd share:

http://paulirish.com/2010/duck-punching-with-jquery/


Sep 14, 2010 at 9:13 PM // reply »
11,238 Comments

@Jordan,

Both links worked for me. I like what you're doing. Clearly, this is something very specific to your particular application configuration; but, that said, it looks like it helps unify the API functionality.

@Pomeh,

You could certainly do that; but you still need to create a local variable for the old method reference. Part of what I was demonstrating here was the use of parameter-argument mapping to remove the local variable. Again, no functional difference, just something I liked about it. I like that you don't have to repeat the function name, however - nice idea.

@Alex,

Ha ha, yeah "Duck Punching" is definitely a more catchy phrase.... although, Aspect Oriented Programming sounds very sophisticated.


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
May 20, 2013 at 4:29 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, That's if you're trying to reference a specific row. In this case, we're trying to reference the entire query column as one cohesive value. So, you are correct that if you wanted to output a ... read »
May 20, 2013 at 4:24 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I thought when you used array notation to reference queries you always had to have the row or it would throw a similar error as well? ... read »
May 20, 2013 at 11:45 AM
Using jQuery's Animate() Step Callback Function To Create Custom Animations
This is really useful. I found out that you don't actually have to use a dummy css property (surprisingly). To animate a property in a linear-gradient for instance I did this this.css('someLinearGra ... read »
May 20, 2013 at 10:51 AM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Josh, Oh snap! You're totally right! I'm not sure I've ever tried that. I did know that you can call a number of other array-methods on ColdFusion query columns: http://www.bennadel.com/blog/167 ... read »
May 20, 2013 at 10:45 AM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Ben - I believe you can achieve the same functionality with ColdFusion's built in ArrayToList() function. ArrayToList( users[ "id" ] ); ... read »
May 20, 2013 at 10:21 AM
My Experience With AngularJS - The Super-heroic JavaScript MVW Framework
Is there any error logging and handling framework in angularjs, if not then in what way I can do this. ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools