Method overloading in javascript/prototype

Outlined in this post by John Resig (Mozilla nut and general JavaScript guru) is an idea on how to implement method overloading in JavaScript.

The idea in general is good, but honestly, using only parameter count as the way to distinguish between functions can be a bit limiting in my opinion, so here is my take on it, which builds on prototypes object model.

Also an important part of me is aesthetics, and I like the way that prototype declares its methods. Here is the syntax I came up with:

var Test = Class.create({
  initialize: function () 
  {
    console.log('init');
  },

  // regular method
  test1: function (num, str)
  {
    console.log('test1(num:'+ num + ',str:"' + str + '")');
  },

  // overloading using an array of functions with different
  // parameter counts
  test2: [
          function (a)
          {
            console.log('test2(a:"' + a + '")');
          },

          function (a, b)
          {
            console.log('test2(a:"' + a + '",b:"' + b + '")');
          }
        ],

  // overloading using an array of objects that specify
  // the function parameter signature and the functions
  // themselves
  test3: [
          {
            signature: [String],
            method: function (str)
            {
              console.log('test3(str:"' + str + '")');
            }
          },

          {
            signature: [Number],
            method: function (num)
            {
              console.log('test3(num:' + num + ')');
            }
          },

          {
            signature: [Number, String],
            method: function(num, str)
            {
              console.log('test3(num:'+ num + ',str:"' + str + '")');
            }
          }
        ]
});

Using the following test script:

var test = new Test();
test.test1(1, 'test string 1');
test.test2('test string 2');
test.test2('test string 3', 'test string 4');
test.test3('test string 5');
test.test3(2);
test.test3(3, 'test string 6');

We get the following output in Firebug/Firebug light:

init
test1(num:1,str:"test string 1")
test2(a:"test string 2")
test2(a:"test string 3",b:"test string 4")
test3(str:"test string 5")
test3(num:2)
test3(num:3,str:"test string 6")

All in a nice and neat little package. Here is the actual code. Plug it into your site wherever appropriate:

Function.prototype.getName = function ()
{
  var name = /\W*function\s+([\w\$]+)\(/.exec(this.toString());
  if (!name)
    return 'No name';
  return name[1];
};

Class.Methods.addMethods = Class.Methods.addMethods.wrap(
  function (callOriginal, source)
{
  var properties = Object.keys(source)

  for (var i = 0, length = properties.length; i < length; i++)
  {
    var property = properties[i], methods = source[property];
    if (methods instanceof Array)
    {
      if (methods.all(function (m) { 
        return typeof m == 'function'; }))
      {
        source[property] = function (methods)
        {
          var args = $A(arguments);
          args.shift();
          methods.each(function (m)
          {
            if (m.length == args.length)
              m.apply(this, args);
          }, this);
        } .bind(this, methods);
      }
      else if (methods.all(function (m) { 
        return typeof m == 'object'; }))
      {
        methods.each(function (m) { 
          m.signature = m.signature.inject([], 
          function (s, v) { return s + v.getName(); }) });
        source[property] = function (methods)
        {
          var args = $A(arguments);
          args.shift();
          var argSig = args.inject([], function (s, v) 
            { return s + v.constructor.getName(); });
          methods.each(function (m)
          {
            if (m.signature == argSig)
              m.method.apply(this, args);
          }, this);
        } .bind(this, methods);
      }
      else
        throw 'Unknown contents of overload array';

    }
  }
  callOriginal(source);
});

Testing using Prototype 1.7 and Firefox 4.0, Chrome 11.0, Internet Explorer 9.0 (+compatibility mode), Opera 11.01, Safari 5.0.4.

This entry was posted in Javascript, Programming and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>