Functional Programming in JavaScript and Following the DRY Principle
Introduction
We all have used JavaScript and probably have felt in love with it. If not, I don't blame you! Its not that easy of a language to work with. However, JavaScript does provide some amazing features that you can leverage to write very clean code to follow the DRY principle. One of those features is Functional Programming.
Example
We all have used multiple built in methods in JavaScript, and have felt in love with it. Lets one of them here:
1. Classic Foreach
const array = [1, 2, 3, 4, 5];
array.forEach((item) => {
console.log(item);
});
Here each item of array is iterated over once and certain operation is performed. But if we take a closer look, the actual implementation of forEach
is hidden from us. We have no idea how it is written in the spec of the language. We only know how to use it (This is called Abstraction in programming). And yet, we can pass almost any valid JavaScript statement and it does the job! How? This is the beauty of Functional Programming. We as programmers can provide a function itself that can perform certain task for us.
The alternative to this forEach
method would be a traditional for loop as
const array = [1, 2, 3, 4, 5];
for (let i = 0; i < array.length; i++) {
console.log(array[i]);
}
Note: I agree that traditional for loop
is way faster than its forEach
counterpart, but lets give that a pass it for now.
Now, what is the problem with this? Why not use a traditional for loop
and why to use the forEach
method?
Well the answer is only for better readability. However, if the amount of data to iterate over is not large, then using forEach
over traditional for loop
doesnot provide much performance boost.
How is it implemented?
Okay. Enough of the performance jibber jabber. Lets see how is it implemented.
Now, we all know that functions can be assigned to variables in javascript.
const fnName = function (...args) {
return;
};
This is a valid statement. If you dont come from a background of statically typed languages, this might seem trivial, but believe me its next to magic that we can do this. Golang
supports this btw even though it is a statically typed language, but most others donot. C/C++
, JAVA
, C#
donot support functions as variables. Infact, C#
uses delegates to do what JavaScript
does.
Your Point?
The magical thing this lets us do is pass functions as arguments to other functions!
Huh? What?
You know like any variable in JavaScript can be passed as argument to other functions like this?
function sum(a, b) {
return a + b;
}
function init() {
const aNum = 12;
const bNum = 40;
const sum = calcSum(aNum, bNum);
}
init();
Likewise, we can pass functions itself! Woah! What? Lets see an example:
function callOtherFunction(functionName) {
functionName();
}
function init() {
const functionVariable = function () {
console.log("I am being Called");
};
callOtherFunction(functionVariable);
}
init();
The output you get is
I am being Called
You see the magic? We are calling the function by passing it as a parameter to other function! It is infact breaching its lexical scope!
Okay.... So What?
The Implementation
Lets say we want to iterate over an array of data and log it to the console. Lets write a function that logs any data to console.
function LogValue(data) {
console.log(data);
}
Now, We require an array of data. Lets create one above the LogValue function
const data = [1, 2, 3, 4, 5];
const LogValue = function (data) {
console.log(data);
};
Now, we want to iterate over the data array and run the LogValue function over every item in the array thus, we can create a function that takes array and any action we wish to perform as arguments and simply iterate over the array and run the action function
const data = [1, 2, 3, 4, 5];
const LogValue = function (data) {
console.log(data);
};
function MyForEach(array, action) {
for (let i = 0; i < array.length; i++) {
action(data[i]);
}
}
Finally, lets call MyForEach function by providing data and LogValue as its arguments
const data = [1, 2, 3, 4, 5];
const LogValue = function (data) {
console.log(data);
};
function MyForEach(array, action) {
for (let i = 0; i < array.length; i++) {
action(data[i]);
}
}
MyForEach(data, LogValue);
This will give same output as this block of code
const data = [1, 2, 3, 4, 5];
data.forEach(LogValue);
If you wish to use arrow function instead, we can do this
const data = [1, 2, 3, 4, 5];
function MyForEach(array, action) {
for (let i = 0; i < array.length; i++) {
action(data[i]);
}
}
MyForEach(data, (item) => {
console.log(item);
});
This will provide same output as
const data = [1, 2, 3, 4, 5];
data.forEach((item) => {
console.log(item);
});
Now for the final show, we see that our implementation doesnot looks as good as the in built one right? I mean while using arrow function we cant even say what is going on in our code. In the native implementation we see that the code is far more readable. Well fear not! We can easily add our implementation to the existing Array method's prototype to use it in just the same way as the traditional forEach method
const data = [1, 2, 3, 4, 5];
/*
* Instead of this,
* function MyForEach(array, action){
* for(let i=0; i<array.length; i++){
* action(data[i])
* }
* }
* MyForEach(data, item=>{
* console.log(item)
* })
*/
Array.prototype.MyForEach = function (action) {
for (let i = 0; i < this.length; i++) {
action(this[i]);
}
};
data.MyForEach((item) => {
console.log(item);
});
You can use this method now to do everything that forEach
does in JavaScript!
Isnt it remarkable that you can do this? This can lead to you not repeating yourself, essentially making you follow the DRY principle.
Write a generic function once and use it wherever on your project!
Conclusion
JavaScript is filled with fun things like this that you can explore and imporove your approach in writing code. Making a habit of utilizing the language with many features that it provides will help you become a better developer.
I will leave you here with the implementation of the most useful map
method used in JS array that returns another array by performing an operation. I hope you liked this blog, and I hope this helped you get into more complex and advanced topic in JavaScript
.
The Map Method
Array.prototype.MyMap = function (action) {
const newArray = [];
for (let i = 0; i < this.length; i++) {
newArray.push(action(this[i]));
}
return newArray;
};
function init() {
const data = [4, 5, 6, 7, 8, 9];
//JS Built Implementation of Map
const jsMapAns = data.map((item) => {
return item + 5 * 3;
});
//My Implementation of Map
const myMapAns = data.MyMap((item) => {
return item + 5 * 3;
});
console.log(jsMapAns, myMapAns, jsMapAns.toString() === myMapAns.toString());
}
init();