JavaScript style for optional callbacks
Solution 1:
I personally prefer
typeof callback === 'function' && callback();
The typeof
command is dodgy however and should only be used for "undefined"
and "function"
The problems with the typeof !== undefined
is that the user might pass in a value that is defined and not a function
Solution 2:
You can also do:
var noop = function(){}; // do nothing.
function save (callback){
callback = callback || noop;
.....do stuff......
};
It's specially useful if you happen to use the callback
in a few places.
Additionally if you are using jQuery
, you already have a function like that, it's called $.noop
Solution 3:
Simply do
if (callback) callback();
I prefer to call the callback if supplied, no matter what type it is. Don't let it fail silently, so the implementor knows he passed in an incorrect argument and can fix it.
Solution 4:
ECMAScript 6
// @param callback Default value is a noop fn.
const save = (callback = () => {}) => {
callback(); // Executes callback when specified otherwise does nothing
};
Solution 5:
Rather than make the callback optional, just assign a default and call it no matter what
const identity = x =>
x
const save (..., callback = identity) {
// ...
return callback (...)
}
When used
save (...) // callback has no effect
save (..., console.log) // console.log is used as callback
Such a style is called continuation-passing style. Here's a real example, combinations
, that generates all possible combinations of an Array input
const identity = x =>
x
const None =
Symbol ()
const combinations = ([ x = None, ...rest ], callback = identity) =>
x === None
? callback ([[]])
: combinations
( rest
, combs =>
callback (combs .concat (combs .map (c => [ x, ...c ])))
)
console.log (combinations (['A', 'B', 'C']))
// [ []
// , [ 'C' ]
// , [ 'B' ]
// , [ 'B', 'C' ]
// , [ 'A' ]
// , [ 'A', 'C' ]
// , [ 'A', 'B' ]
// , [ 'A', 'B', 'C' ]
// ]
Because combinations
is defined in continuation-passing style, the above call is effectively the same
combinations (['A', 'B', 'C'], console.log)
// [ []
// , [ 'C' ]
// , [ 'B' ]
// , [ 'B', 'C' ]
// , [ 'A' ]
// , [ 'A', 'C' ]
// , [ 'A', 'B' ]
// , [ 'A', 'B', 'C' ]
// ]
We can also pass a custom continuation that does something else with the result
console.log (combinations (['A', 'B', 'C'], combs => combs.length))
// 8
// (8 total combinations)
Continuation-passing style can be used with surprisingly elegant results
const first = (x, y) =>
x
const fibonacci = (n, callback = first) =>
n === 0
? callback (0, 1)
: fibonacci
( n - 1
, (a, b) => callback (b, a + b)
)
console.log (fibonacci (10)) // 55
// 55 is the 10th fibonacci number
// (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...)