If you are like me, you have been using for and while loops for the longest time in JavaScript. I mean if it gets the job done, what’s the problem right? Well, although it gets the job done, when the size of the application and the complexity goes up, it could be a problem.
There are 3 good reasons why you should stop using loops. We will also look at various alternatives to looping that will help us get the task done in a better way.
1. Easy To Read And Maintain
Functional programming is a concept where everything in your application can be boiled down to pure functions. A pure function is one where it takes a set of parameters, does some computation and returns a result. It doesn’t access anything outside of the function, it is pure on its own. Even more, it does one thing and one thing only. The simpler a function, the better. The benefits are: reduced redundancy, modularity and easy to maintain.
What does this has to do with loops? Well, let’s take a look at a simple example. Let’s say we need to take an array, add all the numbers to it and concatenate it to a string:
What does this has to do with loops? Well, let’s take a look at a simple example. Let’s say we need to take an array, add all the numbers to it and concatenate it to a string:
Non-functional Programming way with For Loop:
var numberArray = [1,2,3,4,5,6];
var stringToConcatTo = "Total:";function addNumbersAndConcat(arr, str){
var total = 0;
for (var index = 0; index < arr.length; index++){
total += arr[index]; // Add total
}
str += total.toString(); // Concatenate to the string
return str;
}
// Function Call
this. addNumbersAndConcat(numberArray, stringToConcatTo);
var stringToConcatTo = "Total:";function addNumbersAndConcat(arr, str){
var total = 0;
for (var index = 0; index < arr.length; index++){
total += arr[index]; // Add total
}
str += total.toString(); // Concatenate to the string
return str;
}
// Function Call
this. addNumbersAndConcat(numberArray, stringToConcatTo);
In the above example, the code works as we want it to, however, it deviates from the functional programming concept. The function does more than one computation (Addition code block and Concatenation code block). We could fix this by putting the addition part in a different function and then calling it here. That way, this function just takes the output from the addition function and just concatenates. So in that case it just does the “computation” for concatenation.
Functional Programming way with For Loop:
var numberArray = [1,2,3,4,5,6];
var stringToConcatTo = "Total:";function addArray(arr) {
var total = 0;
for (var index = 0; index < arr.length; index++){
total += arr[index]; // Add total
}
return total.toString();
}function concatToTotal(arr, str){
str += this.addArray(arr); // Concatenate to the string
return str;
}concatToTotal(numberArray, stringToConcatTo); // Function Call
var stringToConcatTo = "Total:";function addArray(arr) {
var total = 0;
for (var index = 0; index < arr.length; index++){
total += arr[index]; // Add total
}
return total.toString();
}function concatToTotal(arr, str){
str += this.addArray(arr); // Concatenate to the string
return str;
}concatToTotal(numberArray, stringToConcatTo); // Function Call
This is good but we can do better if we just eliminate loops. In JavaScript we can use map, reduce and filter. These functions are designed for this purpose. Using them, we make our code easier to read, understand and it keeps it functionally programmed. In our particular case, we will use reduce to improve our code.
Functional Programming way Without Loop:
var numberArray = [1,2,3,4,5,6];
var stringToConcatTo = "Total:";function concatToTotal(arr, str){
str += arr.reduce((acc, currVal) => acc + currVal).toString();
return str;
}concatToTotal(numberArray, stringToConcatTo);
We have refactored our to be strictly function and reduce helped us eliminate loops to make it compact, easier to read and easy to maintain in the future.
var stringToConcatTo = "Total:";function concatToTotal(arr, str){
str += arr.reduce((acc, currVal) => acc + currVal).toString();
return str;
}concatToTotal(numberArray, stringToConcatTo);
We have refactored our to be strictly function and reduce helped us eliminate loops to make it compact, easier to read and easy to maintain in the future.
2. Composability
The functions map, reduce and filter provided by JavaScript array class, for instance, are versatile and supports composability. Composability simply means, you can do one thing in a function, then pass the output to the next function and then to the next to get a final output. It is like chaining multiple loops but prettier.
Let’s take an example: You are supposed to create a feature in your web app. It returns the name of the sales person with most sales.
var nameList = [
{
"name": "Alice", "role": "Accountant", "papers_sold": 0
},
{
"name": "Bob", "role": "Sales", "papers_sold": 1000
},
{
"name": "Charles", "role": "Accountant", "papers_sold": 0
}
{
"name": "Dan", "role": "Sales", "papers_sold": 1200
}
{
"name": "Emily", "role": "Sales", "papers_sold": 1600
}
]
First we need to separate Sales from Accountants. Then, we need to find out the sales person with the maximum number of papers sold.
Traditionally, we would use a for loop to go over the array. Make a new array with only sales people. Then we go over it find the person with most sales. It would end up looking much uglier and more complex looking than it needs to.
However, by composing filter and reduce we can do this like so
function bestRecordInDept(nameList, role){
return nameList
.filter(record => record.role === role)
.reduce((acc, value) => {
// Replace with the greater value
acc = acc.papers_sold > value.papers_sold ? value : acc;
return acc.name;
}, {})
}
Here we used filter to filter out records with only Sales as the role and then reduced the data to the name of the salesperson with the most amount of papers sold. We were able to compose filter and reduce here without modifying the original array which brings us to our next point.
Let’s take an example: You are supposed to create a feature in your web app. It returns the name of the sales person with most sales.
var nameList = [
{
"name": "Alice", "role": "Accountant", "papers_sold": 0
},
{
"name": "Bob", "role": "Sales", "papers_sold": 1000
},
{
"name": "Charles", "role": "Accountant", "papers_sold": 0
}
{
"name": "Dan", "role": "Sales", "papers_sold": 1200
}
{
"name": "Emily", "role": "Sales", "papers_sold": 1600
}
]
First we need to separate Sales from Accountants. Then, we need to find out the sales person with the maximum number of papers sold.
Traditionally, we would use a for loop to go over the array. Make a new array with only sales people. Then we go over it find the person with most sales. It would end up looking much uglier and more complex looking than it needs to.
However, by composing filter and reduce we can do this like so
function bestRecordInDept(nameList, role){
return nameList
.filter(record => record.role === role)
.reduce((acc, value) => {
// Replace with the greater value
acc = acc.papers_sold > value.papers_sold ? value : acc;
return acc.name;
}, {})
}
Here we used filter to filter out records with only Sales as the role and then reduced the data to the name of the salesperson with the most amount of papers sold. We were able to compose filter and reduce here without modifying the original array which brings us to our next point.
3. Immutability
More often than not, by using loops we end up modifying the original array that we were looping in. This can cause bugs that are hard to track. By mutating the contents of the array at more than one place, we could cause some serious undesired “features” if we are not careful.
Using innate JavaScript prototype functions like map we eliminate this possibility. This is because, map never modifies the original array. It always return a new array. This makes your original array immutable, thus preventing possibility of any future bugs in this regard.
Let’s say you need to see what giving everybody a raise by 2% looks like. This means you need to leave the original record as is. You just need to see some stats to prepare for the future.
If you use the traditional loop to do this it might look something like this:
var newNameList = nameList;
for (var index = 0; index < newNameList.length; index++){
newNameList[index].salary = newNameList[index].salary*0.25;
}
console.log(newNameList);
Here’s, the problem. When you assign an array to another array it creates a copy by reference. Meaning, when you modify the newNameList salary, the salary within nameList(your original array) will also change. That’s not good.
One way is to create a copy of the array by value. You can achieve this by using slice on the array like so: nameList.slice();
However, we can avoid this whole issue by simply using map like this:
console.log(nameList.map(x => x.salary += x.salary* 0.02));
So much cleaner and no mutation.
Using innate JavaScript prototype functions like map we eliminate this possibility. This is because, map never modifies the original array. It always return a new array. This makes your original array immutable, thus preventing possibility of any future bugs in this regard.
Let’s say you need to see what giving everybody a raise by 2% looks like. This means you need to leave the original record as is. You just need to see some stats to prepare for the future.
If you use the traditional loop to do this it might look something like this:
var newNameList = nameList;
for (var index = 0; index < newNameList.length; index++){
newNameList[index].salary = newNameList[index].salary*0.25;
}
console.log(newNameList);
Here’s, the problem. When you assign an array to another array it creates a copy by reference. Meaning, when you modify the newNameList salary, the salary within nameList(your original array) will also change. That’s not good.
One way is to create a copy of the array by value. You can achieve this by using slice on the array like so: nameList.slice();
However, we can avoid this whole issue by simply using map like this:
console.log(nameList.map(x => x.salary += x.salary* 0.02));
So much cleaner and no mutation.
Performance Concerns
When used properly, the performance difference between traditional loops and map, reduce and filter are negligible.
There are two major factors to consider:
Iterations: As long as you are maintaining the same amount of iterations or less using map, reduce and filter compared to traditional loops, you should be good.
Size of the data: For extremely large data, for instance, 1 million data records, you are probably better off with a for loop with a break in between if necessary. In my tests, there was a small difference of about 0.2–0.3 seconds and no more. Of course, bigger the data, the more significant the difference would be.
There are two major factors to consider:
Iterations: As long as you are maintaining the same amount of iterations or less using map, reduce and filter compared to traditional loops, you should be good.
Size of the data: For extremely large data, for instance, 1 million data records, you are probably better off with a for loop with a break in between if necessary. In my tests, there was a small difference of about 0.2–0.3 seconds and no more. Of course, bigger the data, the more significant the difference would be.
So when should you use loops?
Most programmers are used to think about a problem which requires iteration and go straight to using loops since that’s what we were started with and used so much. This article, more than anything, is an effort to move you away from that mindset when you think about problems. It doesn’t mean you need to discard loops altogether.
There are two simple questions I ask myself to figure out if I need a loop or not:
There are two simple questions I ask myself to figure out if I need a loop or not:
- Is performance impacted significantly?
- Am I just trying to make my code look cooler? The objective is to make it simple to read for the future you. Over-engineering will only make it harder to maintain.
If the answer to both these questions are yes, only then I go for loops.
Read More :: 13 VSCode Extensions That Every Web Developer Should Use
Read More :: 8 VS Code Plugins To Improve Your Productivity
Conclusion
I hope has helped to influence the way you code and think about problems in the future. I’d love to hear your thoughts. Do you agree? Disagree? Let me know in the comments.
Tags :: how to use loops in python,how to use loops in java,how to use loops,how to use for loop in javascript,loops python,for loops in python,loops meaning,for loop in javascript,loops javascript,loops in c,for loops java,loops java,loop while,for loop in php,while loops in c,for loops in matlab,loops,loops meaning in hindi,loops in c
Tags
for loop in javascript
for loop in php
for loops in python
for loops java
how to use for loop in javascript
how to use loops
loop while
loops in c
loops java
loops javascript
loops meaning
.reduce(), .filter(), .map() are all loops too, just sugary and slower.
ReplyDeleteDealing with arrays without loops would actually mean using recursion or proxy treachery.