My favorite functional adaptors

unary, once, time, fluent and tap

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
2
['1', '2', '3'].map(parseInt); // [1, NaN, NaN]
['1', '2', '3'].map(ignoreArgument(parseInt, false, true)); // [1, 2, 3]

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
2
3
4
5
if (fs.existsSync(filename)) {
}
// add time info
if (time(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
2
3
4
5
6
var out = {
log: function () {
console.log.apply(console, arguments);
return this;
}
};

You can make the fluent support very obvious by using allong.es fluent function

1
2
3
4
5
6
7
var fluent = require('allong.es').es.fluent;
var out = {
log: fluent(function () {
console.log.apply(console, arguments);
})
};
out.log('something').log('or').log('other');
// prints
something
or
other

tap

Often multiple function calls are composed into a single function

1
2
3
4
5
6
7
8
9
10
11
function mul(a, b) {
return a * b;
}
function div10By(x) {
return 10 / x;
}
var _ = require('lodash');
var log = _.bind(console.log, console);
var mulAndDiv = _.flow(mul, div10By, log);
mulAndDiv(2, 5);
// 1

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
2
3
var log = _.bind(console.log, console);
var mulAndDiv = _.flow(mul, log, div10By, log);
mulAndDiv(2, 5);
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
2
3
4
5
6
7
8
function tap(fn) {
return function tapped(x) {
fn.apply(null, arguments);
return x;
};
}
var mulAndDiv = _.flow(mul, tap(log), div10By, log);
mulAndDiv(2, 5);
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
2
3
4
5
Q.when(...) // some promise or value
.then(tap(log))
.then(div10By)
.then(log)
.done();

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.