'piping functions in JavaScript
How can I have a JavaScript function let's say piper() which takes several functions as its arguments and it returns a new function that will pass its argument to the first function, then pass the result to the second, then
pass the result of the second to the third, and so on, finally returning the output of the last function.
Something like piper(foo, fee, faa)(10, 20, 30) would be equivalent to calling faa(fee(foo(10,20,30))).
ps: It was a part of an interview, that I did few days ago.
Solution 1:[1]
Enjoy. Pure ES5 solution. Preserves this.
function piper(){
var i = arguments.length,
piped = arguments[ --i ];
while( --i >= 0 ){
piped = pipeTwo( arguments[ i ], piped );
}
return piped;
}
function pipeTwo( a, b ){
return function(){
return a.call( this, b.apply( this, arguments ) );
}
}
Or, if you want the fancy solution.
function piperES6( ...args ){
return args.reverse().reduce( pipeTwo );
}
Loops can be reversed depending on the desired direction.
Solution 2:[2]
Very similar to @trincot's answer (preserves context), but composes in the correct order and is marginally faster since it does not create intermediary arrays:
const piper = (...steps) => function(...arguments) {
let value = steps[0].apply(this, arguments);
for (let i = 1; i < steps.length; ++i) {
value = steps[i].call(this, value);
}
return value;
};
// Usage:
let p = piper(
x => x + 1,
x => x * 2,
x => x - 1
);
console.log(p(2)); // 5
Solution 3:[3]
Here is an alternative answer involving method chaining. I shall use ES6, though of course this can be transpiled to ES5. On benefit of this solution is that is has a very succinct TypeScript counterpart with perfect typeability.
class Pipe {
constructor(value) {
this.value = value;
}
then(f) {
return new Pipe(f(this.value));
}
}
const pipe = value => new Pipe(value);
// Example
const double = x => 2 * x;
pipe(42).then(double).then(console.log); // 84
const result = pipe(42).then(double).then(double).value;
console.log(result); // 168
Solution 4:[4]
A simple solution based on JS higher-order functions usage:
function pipe(...rest) {
return x => rest.reduce((y, f) => f(y), x);
}
Usage:
pipe((a) => a + 1, (a) => a * 2)(3) // 8
pipe((a) => a + 1, (a) => a * 2)(2) // 2
Solution 5:[5]
function f(f1, f2, f3){
return (args => f3(f2(f1(args))));
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Community |
| Solution 3 | |
| Solution 4 | Purkhalo Alex |
| Solution 5 | Isukthar |
