"Extension Method" in JavaScript

I have to admit a secret.  I actually like JavaScript as a programming language — especially now with jQuery and QUnit.  It’s more out of nostalgia for my earlier programming days doing DHTML applications than the fact that JavaScript is now chic in some circles.  

This morning I found myself wanting some sort of method to check whether an Array object contained a value.  I could have written the code inline, but it was cleaner to just add a new method to the Array class.  Using the prototype object, I’ll just add a method called “contains(value)” to all instances of Array:

 Array.prototype.contains = function(value){

     for (var i = 0; i < this.length; i++){

         if (this[i] == value) return true;

     }

 

     return false;

 }

In the middle of my code it’s used like (actions is an array of all the available context menu actions for a row in a table):

 function showMenuItem(actions, item){

     if (actions.contains(item.id)){

         $(item).show();

     }

     else{

         $(item).hide();

     }

 }

 

I’m sure there’s a better way to do what I did above, but dang that was easy.  Yeah, C# has extension methods, but JavaScript had open classes first with fewer restrictions than the C# version.

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Andre Juliano

    Very nice article, easy and straightforward!

  • http://twitter.com/jeremydmiller jeremydmiller

    prototype is intrinsic to JavaScript.  Just do a google search on JavaScript prototype inheritance to get a real explanation.  Probably something you should understand if you’re doing JavaScript.

  • Brandon D’Imperio

    Does the prototype object belong to javascript? supported by which browser(s) (version numbers?)? or is it jQuery’s doing?

  • http://www.bzlab.ru Alexander Byndyu

    It is very good feature for JS!
    I like to use it for custom Array list.

  • ZaM

    Monkey patch!

  • Michael Schall

    Modifying systems objects will bite you. What happens when the next version of JavaScript (EcmaScript) or a browser implementation has a ‘contains’ function with a different signature? Or another library you are using modifies the prototype differently? I want my code to be as future proof as possible. Not polluting the system objects or global namespace is the safest way to code. I use the Dojo Toolkit which follows the no pollution rule.

    Here is a library comparison:
    http://dojotoolkit.org/book/dojo-book-0-9/introduction/why-dojo

  • Dan F

    @Si – don’t loop your arrays that way and the problem goes away – http://www.prototypejs.org/api/array

    @julian – Nope, they’re shared amongst all instances – see the comments about the respondTo method http://msdn.microsoft.com/en-us/magazine/cc163419.aspx#S3

    @Jeremy – Javascript is wonderful :-)

  • http://neilmosafi.blogspot.com Neil Mosafi

    @Si – Great point dude, I had no idea that would happen!!

  • http://breakfastdinnertea.co.uk Si

    You should probably avoid modifying the prototype of system objects, here’s why (run it in the firebug console for best results):

    Array.prototype.contains = function(value){
    for (var i = 0; i < this.length; i++){
    if (this[ i] == value) return true;
    }
    return false;
    };

    var r = ['p','q'];
    for(var i in r) {
    console.log(i);
    }

  • http://weblogs.asp.net/jvano joey

    take what you know about c# and throw it out the window.

    javascript != c#. different programming style. nested functions are everywhere. closures are fun and useful (see module pattern, private member variables, loops and creating event handlers on dom elements).

    @Scott

    JavaScript has been around as long as Ruby … so not sure what you are getting at.

    @Jeremy

    Spend some serious time in JavaScript and you will see the true power of JavaScript. Most people can’t because they lose their intellisense or simply don’t understand JavaScript.

  • http://sshconnection.com Scott

    Did somebody say ruby? No? Oh, then I’ll say it. :)

    Really though, open classes that allow monkey patching are awesome as hell, but can also be dangerous in the wrong hands. Just don’t let yourself be the wrong hands.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Paul,

    I think they’re hard to read, that’s all. I use them, I just don’t like to.

  • Paul Cowan

    @Jeremy,

    Why are nested javascript functions to be avoided?

    The functions in question are added to all JQuery objects which might be much more useful.

  • http://ebersys.blogspot.com Eber Irigoyen

    and why are we comparing javascript/C# again?

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Paul,

    Because despite the usefulness and inevitability of such, I think that nested javascript functions are worth avoiding.

    Besides, the “prototype” way demonstrated the concept a bit more IMO.

  • Paul Cowan

    Why not use the extend function of JQuery:

    jQuery.fn.extend({
    check: function() {
    return this.each(function() { this.checked = true; });
    },
    uncheck: function() {
    return this.each(function() { this.checked = false; });
    }
    });
    $(“input[@type=checkbox]“).check();
    $(“input[@type=radio]“).uncheck();

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @All,

    A colleague told me that there is a jQuery method for this. Note to self: always look at jQuery docs first.

  • http://www.corcoranp.com corcoranp

    It is an emoticon representation of ‘( i )’

  • http://webdevdotnet.blogspot.com Elijah Manor

    What does the light bulb indicate in your code snippet?

  • http://neilmosafi.blogspot.com Neil Mosafi

    Actually there is Array.indexOf() which you can use – but it’s still not supported in all browsers!

  • Stu

    @julian Since the method was defined on the prototype, I believe the implementation is shared between Array instances, rather than copied as you suggest.

    Jeremy, my favourite JS feature is the ability to use map, filter and reduce on arrays. Nice to be able use functional paradigms and also, a great way to optimise js file size too.

  • http://codebetter.com/blogs/jeremy.miller Jeremy D. Miller

    @Adrian,

    That’s what I thought too.

  • Adrian

    The bizarre bit is that JScript doesen’t have contains() built in….oh well its only 2008…..

  • julian jelfs

    the important difference is that in c# there is no performance penalty as it is just translated into a static method call by the compiler for you. In javascript every array object you subsequently create will have that extension whether it is used or not. I think this is why you are advised to be careful about extending the prototype of basic types in javascript. I think it’s OK if it is a function that actually makes sense for all Array objects (such as your example) but it can be easily abused (what can’t?)