Currying in JavaScript
Whilst being an object-oriented language, JavaScript still takes a lot of ideas from functional languages. One which it dosen’t implement though, is the idea of currying.
What’s currying then? You might ask, well, here’s the definition according to wikipedia:
In mathematics and computer science, currying, invented by Moses Schönfinkel and later re-invented by Haskell Curry,[1] is the technique of transforming a function that takes multiple arguments (or more accurately an n-tuple as its argument) in such a way that it can be called as a chain of functions each with a single argument.
So basically, it let’s you fill in some arguments to a function before hand and return a new function which you will subsequently call instead, or default arguments on steroids if you will.
Here’s a few examples of what we could do if JavaScript was capable of currying:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // Array to csc Array.prototype.arrayToCsv = Array.prototype.join.curry("; "); ["Patrik", "Hedman", "Stockholm"].arrayToCsv(); //=> "Patrik; Hedman; Stockholm" // And back String.prototype.csvToArray = String.prototype.split.curry(/;\s*/); ("Patrik; Hedman; Stockholm").csvToArray(); //=> ["Patrik", "Hedman", "Stockholm"] // The undefined parameter will be replaced with the // callback function passed to clicker(); var clicker = document.body.addEventListener.curry("click", undefined, false); clicker(function(){ console.log( "Curryfied click event." ); }); |
Pretty sweet, but it wont work since there is no curry() function in JavaScript, not a problem, implementing one is pretty straightforward:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | Function.prototype.curry = function() { // Save references to this and the arguments so we can // acces them from the closure var fn = this, args = Array.prototype.slice.call( arguments ); return function() { var arg = 0; for ( var i = 0; i < args.length && arg < arguments.length; i++ ) if ( args[i] === undefined ) // If the original argument is undefined // then replace it with the new one args[i] = arguments[arg++]; // Call the original function with the current this as // the context and the newly constructed argument list return fn.apply(this, args); }; }; |
