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 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools