Function Composition
— javascript, functional-programming — 1 min read
Method 1
Uses a loop and eagerly (aka, immediately) calculates the result of one call to pass into the next call.
function compose(...fns) { return function composed(result) { // Copy the array of functions var list = [...fns];
while (list.length > 0) { // Take the last function off the end of the list // and execute it result = list.pop()(result); }
return result; };}
Method 2
Using reduce(..)
.
function compose(...fns) { return function composed(result) { return [...fns].reverse().reduce(function reducer(result, fn) { return fn(result); }, result); };}
Method 3
Still use reduce(..)
, but produce a lazy evaluation function wrapping. We return the result of the reduce(..)
call directly, which is itself a function, not a computed result.
function compose(...fns) { return fns.reverse().reduce(function reducer(fn1, fn2) { return function composed(...args) { return fn2(fn1(...args)); }; });}
The produced wrapped function was similar to the one composed manually below:
// Here we compose 4 functions manually.
// The first function can accept multiple argumentvar fn1 = (...arg) => { console.log("fn1", arg); return arg;};
// Add 2 to each numbervar fn2 = (arg) => { console.log("fn2", arg); return arg.map((x) => x + x);};
// Multiply each number by 2var fn3 = (arg) => { console.log("fn3", arg); return arg.map((x) => x * x);};
var fn4 = (arg) => { console.log("fn4", arg); return arg;};
var myFn = function composed(...args) { return fn4( (function composed(...args) { return fn3( (function composed(...args) { return fn2(fn1(...args)); })(...args) ); })(...args) );};myFn(1, 2, 3); // [4, 16, 36]