In a side project that I’ve been working on I built a quick-and-dirty function for doing simple method overloading. For those of you who aren’t familiar with, it’s just a way of mapping a single function call to multiple functions based upon the arguments they accept.

Here’s the function in question:

// addMethod - By John Resig (MIT Licensed) function addMethod(object, name, fn){ var old = object[ name ]; object[ name ] = function(){ if ( fn.length == arguments.length ) return fn.apply( this, arguments ); else if ( typeof old == 'function' ) return old.apply( this, arguments ); }; }

and here is how you might use it:

function Users(){ addMethod(this, "find", function(){ // Find all users... }); addMethod(this, "find", function(name){ // Find a user by name }); addMethod(this, "find", function(first, last){ // Find a user by first and last name }); }

Or, if you wanted to use it with an object prototype:

function Users(){} addMethod(Users.prototype, "find", function(){ // Find all users... }); addMethod(Users.prototype, "find", function(name){ // Find a user by name }); addMethod(Users.prototype, "find", function(first, last){ // Find a user by first and last name });

And here’s what the end result would look like to the user:

var users = new Users(); users.find(); // Finds all users.find("John"); // Finds users by name users.find("John", "Resig"); // Finds users by first and last name users.find("John", "E", "Resig"); // Does nothing

Obviously, there’s some pretty big caveats when using this:

The overloading only works for different numbers of arguments – it doesn’t differentiate based on type, argument names, or anything else. (ECMAScript 4/JavaScript 2, however, will have this ability – called Multimethods – I’m quite excited.)

All methods will some function call overhead. Thus, you’ll want to take that into consideration in high performance situations.

Now, the secret sauce is all going back to the fn.length expression. This isn’t very well known, but all functions have a length property on them. This property equates to the number of arguments that the function is expecting. Thus, if you define a function that accepts a single argument, it’ll have a length of 1, like so:

(function(foo){}).length == 1

I did some basic testing and this technique seems to work in all modern browsers – please let me know if I’m wrong.

If you’re concerned about adding a function call overhead when binding only a single function, then you can give this version of addMethod a try:

// addMethod - By John Resig (MIT Licensed) function addMethod(object, name, fn){ var old = object[ name ]; if ( old ) object[ name ] = function(){ if ( fn.length == arguments.length ) return fn.apply( this, arguments ); else if ( typeof old == 'function' ) return old.apply( this, arguments ); }; else object[ name ] = fn; }

That one will attach the first bound function with no additional checks – keeping it nice and speedy. Once extra functions are bound, things will slow ever so slightly.

This, also, has the added benefit of being able to bind default “catch all” functions which will handle all the calls that pass through. The result would look something like this:

var users = new Users(); users.find(); // Finds all users.find("John"); // Finds users by name users.find("John", "Resig"); // Finds users by first and last name users.find("John", "E", "Resig"); // Finds all

This function won’t change the world, but it’s short, concise, and uses an obscure JavaScript feature – so it wins in my book.