Practical introduction to Functional Programming with JS

AndreaZanin
3,986 views

Open Source Your Knowledge, Become a Contributor

Technology knowledge has to be shared and made accessible for free. Join the movement.

Create Content

Higher Order Functions

Higher Order Functions are functions that take other functions as parameters, Mind Blown 💥.
We are going to discover how these functions are useful through some examples; in particular, we are going to recreate the logic of the Amazon checkout.

Filter

Filter is a method of arrays. It accepts as argument a test function which should return a boolean, and returns a new array with only the elements for which the test function returned true.

Here is an example:

Get the even numbers in an array
1
2
3
4
5
6
7
function isEven(x){
return x % 2 === 0;
}
const numbers = [12,324,213,4,2,3,45,4234];
const evenNumbers = numbers.filter(isEven);
console.log(evenNumbers);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

As you can see, the function isEven doesn't need to include the logic to handle arrays. This is the great thing about higher order functions: the decision logic is kept separate from the function applying it, so we can reuse it.

Let's try to implement our first piece of logic for the amazon cart: extracting from the cart array all the prime items

Implement `isPrime` and `primeItems`, for the latter use `filter`. The file is on the right

Reject

We can now reuse the isPrime function in conjunction with reject to get all the non-prime items in the cart. The reject function is the opposite of the filter: it creates an array with all the elements but those that satisfy the condition.

Reject is not a built-in function in js, we are going to use the library underscore.js to have it. The syntax is slightly different: _.reject(list, testFunction) where _ is the underscore library

Implement the `notPrimeItems` function using `reject` (you can use functions defined in the previous snippet)

As an optional exercise, you could also implement reject yourself using filter.

Implement the `reject` function using `filter`
1
2
3
const reject = (arr, callback) => //todo
// {...}
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Lambda functions

When defining short functions, it's often convenient to use an alternative syntax called lambda function that allows us to define anonymous functions in a more compact way: ( /*arguments*/ ) => { /*code*/ }. If our function is only a return statement, we can even strip the curly brackets and avoid writing return: ( /*arguments*/ ) => /*value to return*/.

We can rewrite the isEven snippet from before with a lambda function:

Get the even numbers in an array
1
2
3
4
const numbers = [12,324,213,4,2,3,45,4234];
const isEven = (x) => x % 2 === 0
const evenNumbers = numbers.filter(isEven);
console.log(evenNumbers);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Map

Another very useful higher order function is map: it takes a function and applies it to all the elements of an array.
The syntax is identical to filter
E.g.

Squaring all the elements of an array
1
2
3
const numbers = [1,2,3,4,5,6,10,20];
const squares = numbers.map((x) => Math.pow(x,2)); // notice the lambda function :)
console.log(squares);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Now back to our amazon example: we can use map to apply a coupon. The applyCoupon function should apply a 20% discount on all the tech items.

Implement the applyCoupon function

Reduce: one function to rule them all

Reduce is the last higher order function we are going to discuss and it's also the most powerful: in fact, you can implement any list transformation with reduce.
Reduce takes in a callback function and a starting value, the callback function takes as arguments an accumulator and the value of the current element of the array and returns the accumulator to be used in the next cycle. The value returned from the last call of the callback function is the value returned by reduce.

It's easier if I show you some examples:

Multiplying all the elements of an array
1
2
3
const numbers = [2,3,4,5];
const product = numbers.reduce((acc, x) => acc * x, 1);
console.log(product);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Filtering only even numbers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const isEven = (x) => {
return x % 2 === 0;
}
const numbers = [12,324,213,4,2,3,45,4234];
const callback = (acc, x) => {
if (isEven(x)){
acc.push(x)
}
return acc
}
const evenNumbers = numbers.reduce(callback, []);
console.log(evenNumbers);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Implementing map with reduce
1
2
3
4
5
6
7
8
9
10
function map(arr, callback){
return arr.reduce((acc, x) => {
acc.push(callback(x));
return acc;
}, []);
}
// squaring example
const squares = map([1,2,3,4,5], (x) => Math.pow(x,2) );
console.log(squares);
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Now to complete our amazon workflow, write a function that returns the total cost of the order.

Implement the `totalCost` function using `reduce`
Open Source Your Knowledge: become a Contributor and help others learn. Create New Content
1
2
/*
The cart is an array of objects like this:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX