Sometimes, the elegant implementation is a function. Not a method. Not a class. Not a framework. Just a function. | ||
--John Carmack, lead programmer of the Doom video game |
Functional programming is all about decomposing a problem into a set of functions. Often, functions are chained together, nested within each other, passed around, and treated as first-class citizens. If you've used frameworks such as jQuery and Node.js, you've probably used some of these techniques, you just didn't realize it!
Let's start with a little JavaScript dilemma.
Say we need to compile a list of values that are assigned to generic objects. The objects could be anything: dates, HTML objects, and so on.
var obj1 = {value: 1}, obj2 = {value: 2}, obj3 = {value: 3}; var values = []; function accumulate(obj) { values.push(obj.value); } accumulate(obj1); accumulate(obj2); console.log(values); // Output: [obj1.value, obj2.value]
It works but it's volatile. Any code can modify the values
object without calling the accumulate()
function. And if we forget to assign the empty set, []
, to the values
instance then the code will not work at all.
But if the variable is declared inside the function, it can't be mutated by any rogue lines of code.
function accumulate2(obj) { var values = []; values.push(obj.value); return values; } console.log(accumulate2(obj1)); // Returns: [obj1.value] console.log(accumulate2(obj2)); // Returns: [obj2.value] console.log(accumulate2(obj3)); // Returns: [obj3.value]
It does not work! Only the value of the object last passed in is returned.
We could possibly solve this with a nested function inside the first function.
var ValueAccumulator = function(obj) { var values = [] var accumulate = function() { values.push(obj.value); }; accumulate(); return values; };
But it's the same issue, and now we cannot reach the accumulate
function or the values
variable.
What we need is a self-invoking function.