To understand Functional JavaScript and the quirks of JavaScript, we will have to look into the history of JavaScript and how it was created.
When Brendan Eich created JavaScipt, he borrowed features heavily from Self
and Scheme
.
Self
Self is a powerful somewhat unusual Object Oriented system.
JavaScript borrowed following features from Self:
- Dynamic dispatch
- Encapsulation
- Polymorphism — lots of it (weak typing!)
- Inheritance through the prototype chain
- Open recursion — through this
Scheme
But it was Scheme, that JavaScript borrowed most important features of functional languages.
- First class functions
- Closures
What's the difference between OOP and FP
There are some significant differences in these two paradigms. OO focuses on the differences in the data, while FP concentrates on consistent data structures.
So here we are going to concentrate on the first-class functions.
Composing
Composing multiple functions to create more complex ones is a common utility in any programming language. And the ability to construct functions in a way that is easily composable is a true talent, but it really helps with code maintenance and reuse. It's not uncommon to find huge applications composed of many, much smaller functions.
Functional Composition
Functional Composition chains together functions to create a new function.
First things first, let's setup some basic test functions:
var add,
multiply,
square,
sum;
add = function(n) { return n + 1; };
multiply = function(n) { return n * 2; };
square = function(n) { return n * n; };
sum = function(x, y) { return x+ y; };
Mathematical Composition
In mathematics f ∘ g
(pronounced f composed with g) is the function that given x, returns f(g(x)). So if we follow the mathematical model compose(add1, square)(x) should equal add1(square(x)).
To compose functions together, we will need to accept a list of functions for it to be made up from (eg: a, b, and c). Now need to call each of them with the result of the next function. In JavaScript, we would do this with a(b(c(x))) (x being the starting value). However, it would be much more useful to have something a little more reusable than this.
var compose = function(f, g) {
return function() {
return f.call(this, g.apply(this, arguments));
};
};
The above function iterates over the function list (our arguments) in reverse - the last function to pass in is executed first. Given a single value as the initial input, it'll chain that value between every function call and return the final result. This allows us to do some really cool things.
var run = compose(add, multiply);
run(22); // 45
Sequence
Sequence is similar to compose
but the arguments are executed in reverse.
var sequence = function(f, g) {
return function() {
return g.call(this, f.apply(this, arguments));
};
};
we can reuse the compose function to write the sequence implementation.
var run = sequence(add, multiply);
run(22); // 46
Reduce
Reduce combines an array into a single value by repeatedly using a function that combines an element of the array with a base value.
var reduce = function(combine, base, array) {
var i,
len = array.length;
for(i = 0; i < len; i++) {
base = combine(base, array[i]);
}
return base;
};
Now we can write a function for sum.
sum([1, 2, 3]); // 6
ForEach
ForEach goes over an array, applying a function to every element
function forEach(array, fn) {
var i,
len = array.length;
for(i = 0; i < len; i++) {
fn(array[i]);
}
}
Now we can write an implementation for forEach function.
var result = 0;
forEach([1, 2, 3], function(element) {
result = result + element;
}); // 6
Array.prototype.forEach()
ES5 forEach()
method executes a provided function once per array element.
Map
Map goes over an array, applying a function to every element, just like forEach. But instead of discarding the values returned by function, it builds up a new array from these values.
function map(array, fn) {
var result = [],
i,
len = array.length;
for(i = 0; i < len; i++) {
result.push(fn(array[i]));
}
return result;
}
Now we can write an implementation for map function.
map([1, 2, 3], function(element) {
return element + 1;
}); // [2, 4, 6]
Array.prototype.map()
EES5 map()
method creates a new array with the results of calling a provided function on every element in this array.
You can find the source code for this tutorial in GitHub.