Skip to content

Instantly share code, notes, and snippets.

@ericelliott
Created June 24, 2011 08:05
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ericelliott/1044413 to your computer and use it in GitHub Desktop.
Save ericelliott/1044413 to your computer and use it in GitHub Desktop.
Polymorphic functions and multiple dispatch in JavaScript
var args = [].slice.call(arguments, 0);
(function () {
var methods = {
init: function (args) {
console.log('initializing...');
return this;
},
hello: function (args) {
console.log('Hello, ' + args);
return this;
},
goodbye: function (args) {
console.log('Goodbye, ' + args);
return this;
}
};
function myModule(options) {
var args = [].slice.call(arguments, 0),
initialized = false,
action = 'init'; // init will run by default
if (typeof options === 'string' &&
typeof methods[options] === 'function') {
action = options;
args.shift();
}
return methods[action].apply(this, args);
}
myModule(); // initializing...
myModule('hello', 'world!'); // Hello, world!
myModule('goodbye', 'cruel world!'); // Goodbye, cruel world!
// We're just chaining the global object here, but jQuery is a good example
// of what's possible...
myModule('hello', 'chaining!')
.console.log('Function polymorphism and method dispatch are easy.');
}());
function morph(options) {
var args = [].slice.call(arguments, 0),
animals = 'turtles'; // Set a default
if (typeof options === 'string') {
animals = options;
args.shift();
}
console.log('The pet store has ' + args + ' ' + animals);
}
morph('cats', 3); // The pet store has 3 cats
morph('dogs', 4); // The pet store has 4 dogs
morph(2); // The pet store has 2 turtles
function sort() {
var args = [].slice.call(arguments, 0);
console.log(args.sort()); // Prints [ 'a', 'b', 'c' ]
console.log(args.shift(), args); // Prints a [ 'b', 'c' ]
}
sort('b', 'a', 'c');
(function () {
function sort() {
// arguments is an array-like object, but it's missing useful array
// functions. We can instantiate a real array, and delegate a call to
// the the slice method to it.
// Notably, this is both shorter and faster than the commonly used
// Array.prototype.slice.call approach.
// Slice is an easy way to shallow-copy an array (or in this case, an
// array-like object).
var args = [].slice.call(arguments, 0);
// Now that args is a real array, we can use the sort method to sort the
// contents. Yay!
console.log(args.sort()); // Prints [ 'a', 'b', 'c' ]
// This is really handy to grab the first argument off the stack:
console.log(args.shift(), args); // Prints a [ 'b', 'c' ]
}
sort('b', 'a', 'c');
// One common use of this pattern is to change the behavior of a function
// depending on what gets passed into it. This is called a polymorphic
// function:
function morph(options) {
var args = [].slice.call(arguments, 0),
animals = 'turtles'; // Set a default
if (typeof options === 'string') {
animals = options;
args.shift();
}
console.log('The pet store has ' + args + ' ' + animals);
}
morph('cats', 3); // The pet store has 3 cats
morph('dogs', 4); // The pet store has 4 dogs
morph(2); // The pet store has 2 turtles
}());
/* This gets really interesting in the context of a module.
*
* The goal is to expose a public api for a chainable
* module. If the module is part of a larger framework,
* you might not want to clutter the framework namespace
* with all your module's public methods. Using multiple
* dispatch, we can call methods by passing the method
* name as the first parameter.
*
* This is a great pattern for jQuery plugins:
*/
(function () {
var methods = {
init: function (args) {
console.log('initializing...');
return this;
},
hello: function (args) {
console.log('Hello, ' + args);
return this;
},
goodbye: function (args) {
console.log('Goodbye, ' + args);
return this;
}
};
function myModule(options) {
var args = [].slice.call(arguments, 0),
initialized = false,
action = 'init'; // init will run by default
if (typeof options === 'string' &&
typeof methods[options] === 'function') {
action = options;
args.shift();
}
return methods[action].apply(this, args);
}
myModule(); // initializing...
myModule('hello', 'world!'); // Hello, world!
myModule('goodbye', 'cruel world!'); // Goodbye, cruel world!
// We're just chaining the global object here, but jQuery is a good example
// of what's possible...
myModule('hello', 'chaining!')
.console.log('Function polymorphism and multiple dispatch are easy.');
}());
console.log(args.shift(), args); // Prints a [ 'b', 'c' ]
console.log(args.sort()); // Prints [ 'a', 'b', 'c' ]
@nelsonomuto
Copy link

This is a great example. I have been trying to find an description of polymorphic functions and or method multi dispatch.

@shubhank-srivastava
Copy link

shubhank-srivastava commented Mar 19, 2017

Great example but one thing to note is that the use of polymorphic functions is discouraged in Node because they cannot be optimized by V8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment