Skip to content

Instantly share code, notes, and snippets.

@dschinkel
Forked from ericelliott/args.js
Created October 2, 2018 04:33
Show Gist options
  • Save dschinkel/4b0b70011e33c6c0292c2e6302c7d69a to your computer and use it in GitHub Desktop.
Save dschinkel/4b0b70011e33c6c0292c2e6302c7d69a 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' ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment