Problem
You want to create a generic function, that produces for a given function the partial applied function.
Ingredients
- 2 functions
- the
apply()
method - the
slice()
method
Directions
-
Define a function that accepts another function (the one that should be partial applicable).
function partial(fn /*, args...*/) { ... }
-
Let the function return another function (this will be the partial applicable function).
function partial(fn /*, args...*/) { ... return function() { ... } }
-
Convert all but the first argument to an array by borrowing the
slice()
method.function partial(fn /*, args...*/) { var args = Array.prototype.slice.call(arguments, 1); return function() { ... }; }
-
Convert the arguments of the inner function to an array.
function partial(fn /*, args...*/) { var args = Array.prototype.slice.call(arguments, 1); return function() { var argsInner = Array.prototype.slice.call(arguments, 0); ... }; }
-
Combine the arguments of the outer function with the arguments of the inner function.
function partial(fn /*, args...*/) { var args = Array.prototype.slice.call(arguments, 1); return function() { var argsInner = Array.prototype.slice.call(arguments, 0); var argsAll = args.concat(argsInner); ... }; }
-
Call the passed function using the
apply()
method, passing the combined arguments.function partial(fn /*, args...*/) { var args = Array.prototype.slice.call(arguments, 1); return function() { var argsInner = Array.prototype.slice.call(arguments, 0); var argsAll = args.concat(argsInner); return fn.apply(this, argsAll); }; }
-
Optional: combine the previous three steps.
function partial(fn /*, args...*/) { var args = Array.prototype.slice.call(arguments, 1); return function() { return fn.apply(this, args.concat(Array.prototype.slice.call(arguments, 0))); }; }
-
Voilá, a perfect, tasteful generic function that creates partial applicable functions.
function partial(fn /*, args...*/) { var args = Array.prototype.slice.call(arguments, 1); return function() { return fn.apply(this, args.concat(Array.prototype.slice.call(arguments, 0))); }; } function createPerson(firstName, lastName) { return { firstName: firstName, lastName: lastName } } var createPersonWithFirstNameJohn = partial(createPerson, 'John'); var johnDoe = createPersonWithFirstNameJohn('Doe'); console.log(johnDoe.firstName); // "John" console.log(johnDoe.lastName); // "Doe"
Alternative recipes
- Since ES2015: use rest parameters, fat arrow functions and the spread operator (implementation will follow in a later blog post).