What is the best way(s) to fake function overloading in Javascript?
I know it is not possible to overload functions in Javascript as in other languages. If I neede
Here is an approach that allows real method overloading using parameter types, shown below:
Func(new Point());
Func(new Dimension());
Func(new Dimension(), new Point());
Func(0, 0, 0, 0);
Edit (2018): Since this was written in 2011, the speed of direct method calls has greatly increased while the speed of overloaded methods have not.
It is not an approach I would recommend, but it is a worthwhile thought exercise to think about how you can solve these types of problems.
Here is a benchmark of the different approaches - https://jsperf.com/function-overloading. It shows that function overloading (taking types into account) can be around 13 times slower in Google Chrome's V8 as of 16.0(beta).
As well as passing an object (i.e. {x: 0, y: 0}), one can also take the C approach when appropriate, naming the methods accordingly. For example, Vector.AddVector(vector), Vector.AddIntegers(x, y, z, ...) and Vector.AddArray(integerArray). You can look at C libraries, such as OpenGL for naming inspiration.
Edit: I've added a benchmark for passing an object and testing for the object using both 'param' in arg and arg.hasOwnProperty('param'), and function overloading is much faster than passing an object and checking for properties (in this benchmark at least).
From a design perspective, function overloading is only valid or logical if the overloaded parameters correspond to the same action. So it stands to reason that there ought to be an underlying method that is only concerned with specific details, otherwise that may indicate inappropriate design choices. So one could also resolve the use of function overloading by converting data to a respective object. Of course one must consider the scope of the problem as there's no need in making elaborate designs if your intention is just to print a name, but for the design of frameworks and libraries such thought is justified.
My example comes from a Rectangle implementation - hence the mention of Dimension and Point. Perhaps Rectangle could add a GetRectangle() method to the Dimension and Point prototype, and then the function overloading issue is sorted. And what about primitives? Well, we have argument length, which is now a valid test since objects have a GetRectangle() method.
function Dimension() {}
function Point() {}
var Util = {};
Util.Redirect = function (args, func) {
'use strict';
var REDIRECT_ARGUMENT_COUNT = 2;
if(arguments.length - REDIRECT_ARGUMENT_COUNT !== args.length) {
return null;
}
for(var i = REDIRECT_ARGUMENT_COUNT; i < arguments.length; ++i) {
var argsIndex = i-REDIRECT_ARGUMENT_COUNT;
var currentArgument = args[argsIndex];
var currentType = arguments[i];
if(typeof(currentType) === 'object') {
currentType = currentType.constructor;
}
if(typeof(currentType) === 'number') {
currentType = 'number';
}
if(typeof(currentType) === 'string' && currentType === '') {
currentType = 'string';
}
if(typeof(currentType) === 'function') {
if(!(currentArgument instanceof currentType)) {
return null;
}
} else {
if(typeof(currentArgument) !== currentType) {
return null;
}
}
}
return [func.apply(this, args)];
}
function FuncPoint(point) {}
function FuncDimension(dimension) {}
function FuncDimensionPoint(dimension, point) {}
function FuncXYWidthHeight(x, y, width, height) { }
function Func() {
Util.Redirect(arguments, FuncPoint, Point);
Util.Redirect(arguments, FuncDimension, Dimension);
Util.Redirect(arguments, FuncDimensionPoint, Dimension, Point);
Util.Redirect(arguments, FuncXYWidthHeight, 0, 0, 0, 0);
}
Func(new Point());
Func(new Dimension());
Func(new Dimension(), new Point());
Func(0, 0, 0, 0);