Functional adaptor wraps a function with additional functionality. It returns a new function that you can use in place of the original one.
When writing JavaScript code, I reuse the same several adaptors again and again: unary, once, time, fluent and tap
unary
Strips all arguments but first one before calling a function.
['foo', 'bar'].forEach(console.log);
foo 0 [ 'foo', 'bar' ]
bar 1 [ 'foo', 'bar' ]
The snippet prints too much due to forEach passing 3 arguments to console.log. We can fix this easily by wrapping console.log wrapped in unary adaptor
var unary = require('allong.es').es.unary;
['foo', 'bar'].forEach(unary(console.log));
foo
bar
You can quickly make this adaptor using ignore-argument function.
1 | ['1', '2', '3'].map(parseInt); // [1, NaN, NaN] |
once
If you every need to remember if something has been initialized already, use once
var initialize = once(longAppSetup);
initialize(); // runs longAppSetup
initialize(); // nothing runs
initialize(); // nothing runs
There are two versions available:
- allong.es has once that only returns function's result once, returning undefined afterwards.
- I prefer to use lodash's once that caches the value and returns it on every call.
time
This is my adaptor that times how long a function takes to execute. Handles both sync and promise-returning functions.
1 | if (fs.existsSync(filename)) { |
fluent
Fluent programming allows chaining method calls on an object. jQuery is a great example, allowing to link multiple calls into single chain. You can write fluent interfaces by always remembering to return this from each method's call
1 | var out = { |
You can make the fluent support very obvious by using allong.es fluent function
1 | var fluent = require('allong.es').es.fluent; |
// prints
something
or
other
tap
Often multiple function calls are composed into a single function
1 | function mul(a, b) { |
Each pair of inputs is first multiplied, then the result is passed to the div10By
function,
and then the result is printed. What if we want to see the intermediate result after the multiplication
but before the division? We cannot use console.log
- it does NOT pass the input arguments,
effectively terminating the chain.
1 | var log = _.bind(console.log, console); |
10
NaN
To use the inputs and then pass them unchanged to the next function (return the first one), we can
use the tap
function.
1 | function tap(fn) { |
10
1
The same tap
function works very well inside the promise chains. For example to debug a value passed
asynchronously between the steps
1 | Q.when(...) // some promise or value |
To remove logging, just comment out the .then(tap(log))
line.
Using functional adaptors helps me write concise and expressive code, hope you try them out.