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 »
10,743 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 »
10,743 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
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 16, 2012 at 8:18 PM
Best Of ColdFusion 10 Contest Entry - HTML Email Utility
Just found this, looks good! I'm trying to run it on local, it's the 64bit version and I'm experiencing horrible lag. On average the generate.cfm processes the content change in 60-90 seconds. I've ... read »
May 16, 2012 at 6:40 PM
Maintaining Sessions Across Multiple ColdFusion CFHttp Requests
I am trying to integrate this CFHTTPsession into an application that will log into zeekrewards.com to post ads and I am not having any luck. The code works perfectly for logging into other websites, ... read »
May 16, 2012 at 2:44 PM
Creating A Sometimes-Fixed-Position Element With jQuery
Thank you, very useful technique! Worked like a charm. ... read »
May 16, 2012 at 1:58 PM
Movies As A Religious Experience
Acting can, in a way, ruin the movie-goer's experience. I used to be able to get so caught up in movies and their plots, and totally engaged. But lately, I haven't been able to as much with a lot o ... read »
May 16, 2012 at 1:52 PM
The Science Of Optimal Post-Exercise Nutrition
children of this age eat very less vegetables so u can opt for salads they will like it also carrot ,cucumber,onion and as far as pulses are concerned u can boil them ,give him along with mashed rice ... read »
May 16, 2012 at 1:34 PM
Strange ColdFusion JRUN Stack Overflow Error
Hey, Recently I updated my jrun4 using the latest updater 7 and now i am having memory issues :(:(:( any help is appreciated ... read »
May 16, 2012 at 9:56 AM
ColdFusion 10 Beta, Apache Tomcat, And Symbolic Links On Mac OSX
Hi, Now that ColdFusion 10 is out I have stumbled over this as well and I cannot figure out the proper solution. We're running virtual hosts via Apache2; the ColdFusion-applications store their fil ... read »
May 15, 2012 at 6:03 PM
Movies As A Religious Experience
@Ben, I don't know whether you'd consider this a religious observation, but it seems to me, in a sense, movies multiply how many lives we get to have. Each movie is like a little extra life we get ... read »