Step 6: Loops
April 30, 2021
One of the things that computer programs really excel at is repetition. We can easily write a program that would make a computer perform a given operation hundreds or billions of times with a change of a single number. This is one of the things that makes programming so powerful. Once we have an operation that successfully works on one value, it is fairly easy to scale that operation to work on thousands or even millions of values. A loop is a programming structure that allows us to perform these kinds of repeating, iterative operations. There are a bunch of ways to write loops. Newer ways of creating loops have been introduced to JavaScript with the language's development over the years. One of the most foundational ways of creating a loop is by using a while
loop.
while Loop
A while
loop is a loop that works indefinitely as long as the condition that enables the loop is satisfied. Here is an example of a while
loop. Beware that this is an infinite loop. It would run continuously until we somehow terminate the program.
let x = 0;
while (x < 10) {
console.log("This is an infinite loop.");
}
We start with the keyword while
. We then write a condition next to the while
keyword inside the parenthesis. This loop will run while this condition is true
. We then write the logic that we want to execute inside the loop by using curly brackets. In this example, x
is always going to be smaller than 10
. This means that the loop will always run. This is an infinite loop.
Infinite loops have their uses, but we usually want to have loops that execute a limited amount of times. We can achieve this using a while
loop as well. We just need to ensure that the condition that makes the loop run evaluates to false
after a while.
Here is an example of a while
loop that runs 10 times.
let x = 0;
while (x < 10) {
console.log(x);
x = x + 1;
}
What is different with this loop is that the value of x
does not stay the same. We increase the value of x
by 1
every time this loop runs. x = x + 1
means, take the current value of x
, add 1
to it and assign the new value to be the current value of x
.
Note that we are using the let
keyword when declaring the variable x
since if we were to use const
, we wouldn't be able to assign a new value to x
.
Example: Writing a Countdown Function Using a While Loop
Let's create a function that would countdown from 10 to 1. At the end of the countdown, it should display a given text value.
countdown("Launch!");
// Counts down from 10 to 1. Then displays "Launch!" to the screen.
// 10
// 9
// ...
// Launch!
Let's also make it so that the countdown value would be adjustable. If there is no second argument provided, it should countdown from 10. But a second argument can be passed to customize this value to be anything we want (as long as the given value is above 1).
countdown("Launch!", 3);
// Counts down from 3 to 1. Then displays "Launch!" to the screen.
// 3
// 2
// 1
// Launch!
We should start by writing the skeleton for our function.
function countdown(message, startingNumber = 10) {}
countdown("Launch!");
We will create a while
loop inside the countdown
function and make it start from the startingNumber
. The loop should continue while the startingNumber
is bigger than 0
.
function countdown(message, startingNumber = 10) {
while (startingNumber > 0) {
console.log(startingNumber);
startingNumber = startingNumber - 1;
}
}
countdown("Launch!");
With each iteration of the loop, we are subtracting 1
from the startingNumber
. When the startingNumber
reaches 0
, the loop will stop working.
The final thing that we need to do here is to make use of the message
variable. And let's test it by passing a different startingNumber
.
function countdown(message, startingNumber = 10) {
while (startingNumber > 0) {
console.log(startingNumber);
startingNumber = startingNumber - 1;
}
console.log(message);
}
countdown("Launch!", 15);
We also need to ensure that the user is passing a starting number that is above 1
.
function countdown(message, startingNumber = 10) {
if (startingNumber <= 1) {
console.log("Please enter a number bigger than 1.");
return;
}
while (startingNumber > 0) {
console.log(startingNumber);
startingNumber = startingNumber - 1;
}
console.log(message);
}
countdown("Launch!", 0);
Here we have added a check to see if the startingNumber
is above 1. If it is not we are displaying an error message and returning from the function.
for Loop
Since it is very common to write loops that only execute for a given amount of time, JavaScript has a dedicated structure for it. It is called a for
loop. Here is how to build a for
loop.
for (let counter = 0; counter < 10; counter = counter + 1) {
console.log("This for a for loop");
}
A for
loop has five parts:
- The
for
keyword. - There is a parenthesis next to the
for
keyword. Inside there, the first section is for the initialization of a loop variable. We named this variable to becounter
in this example, but it can be anything we want. - The second section of the parenthesis is the loop condition. The loop will run as long as this condition is
true
. - The third section of the parenthesis is the loop variable incrementation. Here we adjust the loop variable's value so that the loop condition can be satisfied at some point (assuming we are not trying to write an infinite loop).
- The last part of a
for
loop is the body statement. This is what gets executed as part of the loop.
Example: Writing a Countdown Function Using a for Loop
Let's rewrite our previous example using a for
loop.
function countdown(message, startingNumber = 10) {
if (startingNumber <= 1) {
console.log("Please enter a number bigger than 1.");
return;
}
for (
let countdownNumber = startingNumber;
countdownNumber > 0;
countdownNumber = countdownNumber - 1
) {
console.log(countdownNumber);
}
console.log(message);
}
countdown("Launch!", 5);
for
loop collects every expression needed for managing a loop in one place (inside the parenthesis next to the for
keyword). This makes it a bit easier to write and manage a for
loop. When writing a while
loop, there is a risk of forgetting to increment the loop variable and create an unintentional infinite loop. The structure of the for
loop minimizes that risk.
It is worth mentioning that the variable name chosen for for
loops are usually much shorter for legibility. Conventionally, the letter i
is used as a loop variable name. We can update our example to reflect that convention.
function countdown(message, startingNumber = 10) {
if (startingNumber <= 1) {
console.log("Please enter a number bigger than 1.");
return;
}
for (let i = startingNumber; i > 0; i = i - 1) {
console.log(i);
}
console.log(message);
}
countdown("Launch!", 5);
Looping Over Collections
As we have learned earlier arrays and strings are collection-like data types. We can loop over these collections using a while
loop or a for
loop.
Let's write a function that would display every item of a given array on a separate line.
function displayItems(collection) {
for (let i = 0; i < collection.length; i = i + 1) {
console.log(collection[i]);
}
}
const myFavoriteFood = ["pizza", "sushi", "tacos"];
displayItems(myFavoriteFood);
We wrote a for
loop here that starts a loop from number 0
up until the given collection's length, which is equal to 3
in this case. This means that the loop variable will be assigned the values 0
, 1
, and 2
throughout this loop's execution. We can use these values as indices of items of the given collection.
There are built-in array methods that allow us to iterate over a given array since it is such a common operation to perform.
Two of those methods are forEach
and map
.
forEach Method
The array's forEach
method executes a given callback function for every item in the array.
const myFavoriteFood = ["pizza", "sushi", "tacos"];
myFavoriteFood.forEach(function (item, index, arr) {
console.log(item);
console.log(index);
console.log(arr);
});
The forEach
method takes a callback function and provides it with three arguments.
- The first argument is the current item in the iteration.
- The second argument is the index of the current item.
- The third item is the array that we are iterating over.
Using forEach
displaying every item in a given array becomes extremely easy.
const myFavoriteFood = ["pizza", "sushi", "tacos"];
myFavoriteFood.forEach(function (item) {
console.log(item);
});
It is common to use the shorthand function definition syntax (arrow function) when defining inline functions. It reduces the amount of code that we need to write. Let's refactor our example to use an arrow function.
const myFavoriteFood = ["pizza", "sushi", "tacos"];
myFavoriteFood.forEach((item) => {
console.log(item);
});
Example: Multiplier Function
Let's write a function called multiplier that gets an array of numbers. It should multiply every item in the array with a given value (or with 2
if a value is not provided). Then it should return a new array with the updated values. It should look like this:
const arr = [1, 2, 3, 4, 5];
const newArr = multiplier(arr, 3);
console.log(arr); // [1, 2, 3, 4, 5];
console.log(newArr); // [3, 6, 9, 12, 15];
We are displaying the value of both the given array (arr
) and the newArr
to ensure that our function does not change, mutate, the original array. As a general rule, functions should not mutate the given values but return a new value whenever possible.
Let's see how to tackle this example both with a for
loop and using the forEach
method.
This is how we would implement this function using a for
loop.
function multiplier(arr, multiplierNum = 2) {
const result = [];
for (let i = 0; i < arr.length; i = i + 1) {
const currentItem = arr[i];
const newItem = currentItem * multiplierNum;
result.push(newItem);
}
return result;
}
const arr = [1, 2, 3, 4, 5];
const newArr = multiplier(arr, 3);
console.log(arr); // [1, 2, 3, 4, 5];
console.log(newArr); // [3, 6, 9, 12, 15];
We are creating an empty array called result
inside the function body to store the results of our multiplication operation. Then we are creating a for
loop to iterate over the items of an array. We multiply each item with the given multiplierNum
value and then push
this new value into the result
array. We return the result
array after the loop is complete.
Same functionality implemented with forEach
method would look like this.
function multiplier(arr, multiplierNum = 2) {
const result = [];
arr.forEach((item) => {
const newItem = item * multiplierNum;
result.push(newItem);
});
return result;
}
const arr = [1, 2, 3, 4, 5];
const newArr = multiplier(arr, 3);
console.log(arr); // [1, 2, 3, 4, 5];
console.log(newArr); // [3, 6, 9, 12, 15];
It is a very common operation to iterate over arrays and alter the items' values to create a new array. Arrays have a method called map
that makes these kinds of operations much easier.
map Method
A map
method is similar to a forEach
method. We pass a callback function to a map
method that gets executed on every item.
const myFavoriteFood = ["pizza", "sushi", "tacos"];
myFavoriteFood.map((item) => {
console.log(item);
});
As we can see, it looks very similar to the forEach
method. The arguments that the callback function takes are also the same as the forEach
method. The difference is that the map
method results in a new array with the items we return from the callback function.
const myFavoriteFood = ["pizza", "sushi", "tacos"];
const myNewFavoriteFood = myFavoriteFood.map((item) => {
return "ice cream";
});
console.log(myFavoriteFood); // ["pizza", "sushi", "tacos"];
console.log(myNewFavoriteFood); // ["ice cream", "ice cream", "ice cream"];
Using the map
method, we are able to construct a new array consisting of whatever we return
from the callback function.
Writing a multiplier
function is so much easier when using the map
method.
function multiplier(arr, multiplierNum = 2) {
return arr.map((item) => {
return item * multiplierNum;
});
}
const arr = [1, 2, 3, 4, 5];
const newArr = multiplier(arr, 3);
console.log(arr); // [1, 2, 3, 4, 5];
console.log(newArr); // [3, 6, 9, 12, 15];
Probably, we wouldn't even write a separate multiplier
function since the map
method makes it so easy to this operation on the array.
const arr = [1, 2, 3, 4, 5];
const newArr = arr.map((item) => item * 3);
console.log(arr); // [1, 2, 3, 4, 5];
console.log(newArr); // [3, 6, 9, 12, 15];
filter Method
It is a common requirement to go through the items of an array to see if they satisfy a certain condition. For example, imagine having to write a function that would iterate over an array and return all those items that are longer than 4 characters.
function checkLength(arr) {}
const arr = ["pizza", "taco", "egg", "sushi", "ice cream"];
const newArr = checkLength(arr);
console.log(newArr); // ["pizza", "sushi", "ice cream"];
We would need to use a loop
or the forEach
method to implement this function with our knowledge. map
wouldn't be applicable here since map
returns something for each item in an array. Here we don't want to return anything if the item is shorter or equal to 4 characters in length.
function checkLength(arr) {
const result = arr.map((item) => {
if (item.length > 4) {
return item;
}
});
return result;
}
const arr = ["pizza", "taco", "egg", "sushi", "ice cream"];
const newArr = checkLength(arr);
console.log(newArr); // ["pizza", undefined, undefined, "sushi", "ice cream"]
Here is what the implementation would look like using a forEach
method.
function checkLength(arr) {
const result = [];
arr.forEach((item) => {
if (item.length > 4) {
result.push(item);
}
});
return result;
}
const arr = ["pizza", "taco", "egg", "sushi", "ice cream"];
const newArr = checkLength(arr);
console.log(newArr); // ["pizza", "sushi", "ice cream"]
This function achieves what we are trying to do, but there is a better way of doing this. It is by using the filter
method.
function checkLength(arr) {
return arr.filter((item) => {
if (item.length > 4) {
return true;
}
return false;
});
}
const arr = ["pizza", "taco", "egg", "sushi", "ice cream"];
const newArr = checkLength(arr);
console.log(newArr); // ["pizza", "sushi", "ice cream"]
The filter
method takes a callback function that gets provided with the same arguments as forEach
or the map
method. The filter
method iterates over every item and returns a new array that consists of items where the callback function for the item returns true
. The item will not be included in the final array if the callback function is to return a false
or a falsy value (like undefined
).
Summary
In this chapter, we have learned about loops. A loop is a programming structure that allows us to perform repetitive operations easily. There are a bunch of ways to write loops. We have learned about the while
and for
loops. We can use these structures to loop over arrays or write loops that work indefinitely (infinite loops).
When working with collections like arrays or strings, we frequently need to perform operations on every item of that collection.
- Given an array of names, we might want to find a person with a specific name.
- Given an array of numbers, we might want to operate on every number (maybe calculate the square root of all of them.), etc.
This operation of going through every item in a collection is called iteration. We can use while
or for
loops to iterate over arrays, but some array methods are better suited to this task. These are forEach
and map
methods.
A forEach
method allows us to iterate over each item of an array and execute a callback function on those items. The map
method is structurally similar to the forEach
method, but it returns a new array consisting of the values returned from the callback function.
We have also learned about the filter
method that is also structurally similar to forEach
and map
methods. The filter
is similar to the map
method in that it also returns a new array. We can use the filter
method to eliminate the items in an array that we don't need.
Find me on Social Media