This pattern is not "function chaining", because chained (=composed, pipelined) functions work by passing result of one function as an argument to the next one. For example, if you have something like:
str = removeBadChars(str)
str = makeLowerCase(str)
str = convertToURL(str)
you can rewrite this more concisely as
str = chain(removeBadChars, makeLowerCase, convertToURL)(str)
(Exercise: write chain()
).
Your pattern doesn't appear to have a name, probably because it's fairly useless. Mr. Crockford coined the term retursion,
but it doesn't seem to be used widely.
Note that this pattern is essentially anti-functional, because in functional programming we prefer to work with pure functions, while a "retursive" function can only do anything useful as a side effect.
UPD: this reasoning applies to functions that just blindly return itself, like in your example, however, the f()()()
syntax can also be used with functions that return something else on each invocation. In this case, the "root" function accepts a hidden parameter ("accumulator") used to carry state around. A good example of such approach would be chain()
like above, but written in the applicative style: chain(func1)(func2)(func3)
:
function chain(f, fun) {
fun = fun || function(x) { return x };
if(typeof f != "function")
return fun(f);
return function(x) {
return chain(x, function(y) { return f(fun(y)) })
}
}
// Example:
makeLowerCase = function(str) { return str.toLowerCase() };
removeBadChars = function(str) { return str.replace(/\W/g, "") };
makeURL = function(str) { return "http://" + str };
funcs = chain(makeLowerCase)(removeBadChars)(makeURL);
x = funcs('!!! HELLO ???');
alert(x);
In this case, this syntax is used to implement "partial application", because we return a closure which calls the root function yet again, with a predefined second argument.