I have been using map, reduce, filter in my code base for a while but reading "Functional Programming in Javascript" book by Luis Atencio curated my interest in learning it's implementation. Let us understand these "immutable" (in quotes) gems better, and particularly answer why and how questions ?

For better understanding, let us create a class with some properties which we can refer in rest of the blog.

Step 1: Building our example

Assume new batch of software engineers are hired by XYZ company based on certain job requirements. So Developer class is defined to capture those basic properties,

Map 🎯

Company decide to add bonus amount to all newly hired developers. If we want to code this then we perhaps loop through all of these objects and add the additional amount.

In our first two steps we can focus on answering why map ? and later we can look into how map works?

Step 1: Imperative Approach

though we didn't mutate the original data i.e developers, we had to calculate the length of an array and then loop through each element before adding the bonus amount. But if we decide to use map then these things will be abstracted away from us. i.e calculating the length, looping through an array, pushing it to new array. So we can focus on writing required logic. i.e adding bonus amount. Most importantly it returns a new array.

Step 2: Declarative Approach

Approach two embraces functional programming which emphasis more on composition but in either cases looping, handling temp array is abstracted away from us. Also it didn't alter the original developers array. In short, it behaved like a black box.

For example; using map we created new pizza slices πŸ• with cheese toppings from given plain slices. As a foodie i can either eat normal plain(left) or with cheese toppings (right) slices at any given time.

None
figure 1.1: map (black box) example

I hope this helped reasoning why part of the puzzle. Next we will take a step further into knowing map's inner working.

Step 3: Map Dissection

let us implement our own map to understand better, but first there are few things we need to consider while implementing. (a) map works on an array, (b) it doesn't mutate the original array but returns a new one, and (c) takes function as an argument to work on any given array. Based on these three pillars if we were to implement map then it would look like below,

but we often use map on an array, like array.map() but in our example we have passed array as an argument. Hmmm…..can we make our map behave the same as ECMAScript map ?

let us move on to next one, reduce.

Reduce βš–

If we have a requirement to find average salary gain per year based on experience then imperative way would be looping through each object for calculating total experience and total salary of all developers, then divide salary with total experience.

Step 1: Imperative Approach

Though we could do the calculation in one loop, we still had to worry about looping, declaring temporary variable to calculate the total.

Step 2: Declarative Approach

At first this might look little intimidating but the approach is more modular and still follows the immutable convention. ( Note: If you have better way to figure out averageSalPerYear using reduce please let me know, happy to learn )

Step 3: Reduce Dissection

Instead of looking straight to solving our "average salary gain per year" problem, let us start with simpler example ( adding numbers ) first.

Looks good, now let us make use of "myReducer" to achieve the average salary gain from our developers array.

Great, but if we want to use myReducer as prototype chain then the implementation would change to below ( creating new reducer as myNewReducer to keep all implementation different from each other ),

applying both adding numbers and finding average salary gain to our latest prototype chain myNewReduce method.

neat, now lets us move to filter.

Filter πŸ”Ž

If we want to know all developers who has at least 3 years of experience then we can achieve that by filter, but first let us start with imperative approach.

Step 1: Imperative Approach

Looping through developers array to find years of experience and if it matches the required experience then we will add it to result array.

Step 2: Declarative Approach

quick validation to compare if the filtered data is same as imperative filter array data.

Step 3: Filter Dissection

As we did before, we will define our new filter as array prototype method so we can use like array.myNewFilter

Perhaps, if we want to handle all these scenario at once rather than operating independently. Then this opens up the conversation for method chaining .

Chaining πŸ”—

In this section we will look into "adding bonus amount to all our developers, who has at least 3 years of minimum experience and finally calculate the total salary of those developers"

Yay, we are done πŸ™Œ

Almost, what if we want to find out junior or senior developers based on some experience criteria then we would do something like below using map, which will return new array of titles.

Nice, thats exactly what we expected. Let us check our developersCopy array.

if you noticed the new property title has been added to each object, but map suppose to be immutable 🀯.

None
figure 1.2: stack overflow question in 2016

Why didn't it work for us this time ? because Objects are accessed by reference. So changing the object property by reference will mutate the original array of objects ( i.e impure ).

It is possible to avoid mutation if we clone each object before applying map. For more details you can refer this medium blog or stack overflow question. So functional programming is type of implementation rather than a framework.

Lastly, these gems are very concise, and effective but this comes with a hefty price πŸ’°when used against large data set. Below is simulation of one such scenario,

Happy Coding πŸ¦ΈπŸ½β€β™‚οΈ

P.S : I don't understand this "Clap" thing but if you enjoyed the blog then it doesn't hurt to press it πŸ‘