functional javascript w/ composition

node v6.17.1
version: 8.0.1
endpointsharetweet
One of the most important ideas in software development is: keep it simple. The problem is, every developer believes all code they write is simple & beautiful. ... I'm going to avoid wading into the tarpit of defining "Simple Code." Instead I'll show 2 'rules' which have helped me write more testable & adaptable code. 1. Restrict functions to single-purpose. 2. Restrict functions to single-argument (or 2 for (err, value) style). This can be an array or object with many dimensions. You may be wondering how single-purpose functions ever amount to anything useful, well, let me introduce you to my friend, Higher Order Functions/Components. You may know this by other names, icluding "Controller." ======== Example "Higher Order Functions" to do multiple math steps/functions. Using Pure ES2016 - no "frameworks" - just a tape test.
/* @author: Dan Levy <Dan@DanLevy.net> Twittering: @justsml */ const test = require('tape'); // The '_composer' wrapper fn supports reversing execution order, literally only changes the inner fn '_partial' const compose = _composer(); // note: '_composer' defined at the end, read tests first const composeRight = _composer(true); // Define a Pure-at-heart function (https://en.wikipedia.org/wiki/Pure_function) const add5 = n => { n = parseInt(n) + 5 return n; // required } test('sequence of 3 functions', t => { const add15 = compose(add5, add5, add5); t.equals(add15(0), 15) t.equals(add15(5), 20) t.equals(add15('5'), 20) t.end(); }) // Define some Pure-at-heart functions (https://en.wikipedia.org/wiki/Pure_function) const half = n => { n = (parseInt(n) * 0.5).toFixed(2) return n; // required } const square = n => { n = (parseInt(n * n)).toFixed(2) return n; // required } test('sequence of different functions', t => { const add5HalfSquare = compose(add5, half, square); t.equals(add5HalfSquare(5), '25.00', 'I can caz maths?'); // 5+5==10, half(10)==5, 5*5==25.0 t.end(); }) // Plz ignore any 'fanciness' here - the point is the pattern above: // Forward/reverse function chain helper - tldr: this glues other functions toghether function _composer(reverse = false) { // @uglytruth // Returns higher-order-function, executes using Array.reduce syntax (link mdn article). // Starting with the initial arguments, each function is sequentially executed, passing arguments from one function to the next - functions MUST RETURN THE VALUE TO HAND-OFF. // Only supports single param functions - **this is a feature** return function _directionalFunChain() { const fns = Array.from(arguments); return function _partial() { return Array.from(fns) [reverse ? 'reduceRight' : 'reduce']((last, fn) => fn && fn(last) || last, [...arguments]); }.bind(this); } }
Loading…

2 comments

  • posted 7 years ago by brianleroux
    <3 it!
  • posted 7 years ago by thevige
    fantastic

sign in to comment