Problem
You want to create a generic function, that produces for a given function the partial applied function, applying parameters from the right.
Ingredients
- 2 functions
- the
apply
method - the
slice
method
Directions
-
Given: a generic function for partial application (see recipe 9) …
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))); }; }
-
… which could also be written like this:
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); }; }
-
To apply parameters from the right you only need to change the order how the
argsInner
andargsAll
arrays are concatenated.function partial(fn /*, args...*/) { var args = Array.prototype.slice.call(arguments, 1); return function() { var argsInner = Array.prototype.slice.call(arguments, 0); var argsAll = argsInner.concat(args); return fn.apply(this, argsAll); }; }
-
Optional: write this again as an one-liner:
function partial(fn /*, args...*/) { var args = Array.prototype.slice.call(arguments, 1); return function() { return fn.apply(this, Array.prototype.slice.call(arguments, 0).concat(args)); }; }
-
Voilá, a perfect … oh, wait, you might want to rename the function to
partialRight()
.function partialRight(fn /*, args...*/) { var args = Array.prototype.slice.call(arguments, 1); return function() { return fn.apply(this, Array.prototype.slice.call(arguments, 0).concat(args)); }; }
-
Voilá, a perfect generic function that creates partial applicable functions starting from the right.
function createPerson(firstName, lastName) { return { firstName: firstName, lastName: lastName } } var createPersonWithLastNameDoe = partialRight(createPerson, 'Doe'); var johnDoe = createPersonWithLastNameDoe('John'); console.log(johnDoe.firstName); // "John" console.log(johnDoe.lastName); // "Doe"
Alternative recipes
-
Since ES2015: use rest parameters as shown in recipe 15.
const partial = (fn, ...args) => (...argsInner) => fn(...args, ...argsInner); const partialRight = (fn, ...args) => (...argsInner) => fn(...argsInner, ...args);