I was recently asked a question if method overloading in JavaScript was good practise, or even possible, so I thought I'd spread share my thoughts on this to anyone who bothers to read my ramblings. JavaScript doesn't offer method overloading directly but it does offer features that can be used to facilitate overloading. Imagine these C# method signatures,
// Joins 2 strings
public string Join(string a, string b)
{
return a+b;
}
// Joins an array of strings
public string Join(string[] a)
{
return a.join('');
}
Join(new string[2] {'a', 'b'}); // <-- 'ab'
Join('a','b'); // <-- 'ab'
So depending on the arguments passed to the function the correct method will be called. Now this style of overloading isn't possible in JavaScript.
// Joins 2 strings
function join(a, b){
return a+b;
}
// Joins an array of strings
public join(a){
return a.join('');
}
join(['a','b']) // <-- 'ab'
join('a','b') // <-- ERROR! (join is not a function of string)
As I have said JavaScript has no notion of method overloading so all that happens here is that the join function get redefined with the last occurrence of the function definition. However thanks to JavaScript's typeless nature and optional arguments overloading can be achieved (or at least simulated depending on your viewpoint).
function join(a, b){
if(typeof(a) == 'string'){
return a+b
}else{
return a.join('');
}
}
join(['a','b']) // <-- 'ab'
join('a','b') // <-- 'ab'
Fixed! OK so that may seem simple enough and in this case it is but there are 2 things you need to consider before actually putting this into practise.
Signature Detection
Obviously the first thing you need to do when overloading is detect the intention of the user - what method signature are they using. This is the biggest issue you'll probably come across, especially when dealing with arguments of typefunction
or array
. These posts explain the various issues with type detection and functions/arrays but to summarise
- typeof returns "object" for Arrays
- An array created in a frame/iframe does not share the same prototype as another Array in the parent document or another frame/iframe which make instanceof, typeof and [].constructor fail
- Attempting to detect features such as methods (splice, join) and properties (length) can fail if the a non-array has matching methods/properties
- Certain browsers report objects as functions making typeof == function fail
- Host methods (browsers provided methods) sometimes do not report themselves as functions
The list goes on! So you need to be aware of the target browsers quirks and work with them. Another way to detect signature is to use the arguments
psuedo-array but this is only useful in situations where your overloaded methods accepts a varying number of arguments e.g.
function join(a, b){
if(arguments.length == 2){
return a+b
}else{
return a.join('');
}
}
But then this is open to abuse by ignorant/stupid/malicious coders as it doesn't really imply how the function should behave unless commented well (yeah right!!).
Code Bloat
You need to be sure you aren't abusing this overloading strategy as it can lead to spaghetti code. Functions that attempt to do many things with similar signatures result in loads of argument testing and lot's of indented code. jQuery code is riddled with this due to the way almost every method acts as either a setter, bulk setter or getter method and it's run into bugs in the past due to this. Also the jQuery (or $) function is overloaded to do 5 different things so looking at the init function you'll see that it is a big if..elseif..elseif..elseif..else block which is pretty gruesome and breaks extensability and modularity of the code base.
Conclusion
Overloading is possible in JavaScript but needs to be used with caution. Not only can it lead to very hard to find bugs due to type detection in different browsers but it can also make code harder to understand and extend, not to mention that amount of boilerplate code you need to write to detect the correct method signature etc.