Introduction: What is Control Flow?
A computer program is an algorithm that contains a sequence of events. And control flow is set up to execute those events in the correct order. Throughout this sequence of events, decisions are made based on inputs. In colloquial terms, it sounds like: “If this, then… If that, then that…”
Everything discussed below are control flow statements, which you can use to change and interfere with the normal execution of code in JavaScript.
These are all useful ways to write code that can be reused throughout a program, which will help you finish your app faster, make your codebase more concise and run more efficiently.
In this article, you will learn:
- What are conditionals?
- What are the different ways you can write conditionals in JavaScript?
- When and why should you use each type of conditional
- What are loops?
- What kind of loops are available in JavaScript?
- When and why should you use each type of loop
What are Conditionals?
Conditionals are used to decide which certain code blocks are executed, based on the evaluation of a condition. This makes a program more dynamic as it is able to react differently depending on the circumstances at runtime.
There are three different ways you can write conditionals in JavaScript…
Types of Conditional Statements
-
if else
statements - Ternary operators
-
switch
statements
if else
Statements
The purpose of if else
statements is to make binary decisions–either true
or false
–that tell a computer to do something. All decisions are technically binary, and a final decision can be delineated from a series of binary decisions.
Syntax of if else
Statements
if(*condition*) {
*code block*
}
else if(*condition*) {
*code block*
}
else {
*code block*
}
Example Use Case
if (i % 2 === 0) {
console.log(i);
}
A condition is a small equation evaluated into a Boolean result, and it is evaluated at the time the program teaches that block of code. When using if else
statements, you can add as many conditions as you want.
Any string, and indeed anything that is not a falsy value, will be evaluated as true
. And in order to turn any truthy value into a falsy value, simply use a bang operator like so:
if (!a)
To combine conditions, you can add multiple into one conditional statement by using the AND operator &&
or the OR operator ||
.
Ternary Operators
Ternary operators are a shorthand way to write if else
conditional statements. What’s special about them is that they are also right-associative, which means that they can be chained.
When to Use Ternary Operators
They are especially helpful for condensing code in cases where you only have one line of code to run after the evaluation of a condition. This may mean assigning a value or an increment.
Another case where they are helpful is in handling null
values.
Syntax of Ternary Operators
The ternary operator is the only JavaScript operator that takes 3 operands:
- Condition followed by a question mark
?
- Expression to execute if Condition is truthy followed by a colon
:
- Expression to execute if Condition is falsey
Here’s what it looks like:
condition ? exprIfTrue : exprIfFalse;
Example Use Case
This code logs the result of the ternary operator evaluation:
var age = 26;
var beverage = (age >= 21) ? “Beer” : “Juice”;
console.log(beverage);
Handling null
Values
Here’s a code example that allows an operation in the case of a null
value by replacing the variable that is null
:
let greeting = person =>
let name = person ? person.name : `stranger`
return `Howdy, ${name}`
}
Combining Conditions
To combine conditions while using a ternary operator, you must add parentheses around each additional condition, with an intervening AND operator &&
or an OR operator ||
.
Combining Operations
Furthermore, while adding multiple operations, ternary operators can be chained like so:
return condition1 ? value 1 // If ___ then ___
: condition2 ? value2 // else if ___ then ___
: condition3 ? value3 // else if ___ then ___
: value4; // else ___
The equivalent operations would need to be written in far more elaborate form using if else
statements, and would look like this:
if (condition1) {return value1;}
else if (condition2) {return value2;}
else if (condition3) {return value3;}
else {return value4;}
Refactoring if else
Statements
Here’s a situation where a ternary operator could reduce the code written:
let status; // Variable waiting to be assigned a value
if(age > 18) {
status = ‘adult’;
} else {
status = ‘child’;
}
The above code would be translated as such with a ternary operator:
const status = age > 18 ? ‘adult’: ‘child’;
The first value after ?
is returned if true
, and the second value is returned if false
. Placed between the =
and the >
is the condition.
Comparison Operators
Comparison operators always return a boolean value, and they are used in many languages, including JavaScript.
Types of Comparison Operators
-
>
Greater than -
<
Less than -
>=
Greater than or equal to -
<=
Less than or equal to -
==
Loosely equal to- This operator converts values into the same type.
-
!=
Loosely not equal to -
===
Strictly equal to- This operator checks for the same value and the same type.
-
!==
Strictly not equal to
Logical Operators
Local operators are used to connect two or more expressions in order to create a compound expression whose value is derived solely from the meaning of the original expressions and the operator(s) used.
Types of Logical Operators
- And operator
- Or operator
&&
AND Operator
The AND operator requires both values to be true
in order to return true
. And the order of the two values does not affect the outcome. The operator does not check the second condition if the first is false
.
||
OR Operator
The OR operator required either value to be true
to return true
. And it stops at the first condition evaluating as true
.
Non-Boolean Values
Using logical operators in JavaScript involves different semantics compared to other C-like languages.
This is because logical operators can operate on expressions of any type in JavaScript, not just booleans. Following this, logical operators in JavaScript do not always return a boolean value. The value returned will always be the value of one of the two operand expressions.
Return from Logical Operators
&&
and ||
return the value of only one of their operands. This means that A && B
returns the value A
if A
can be coerced into false
; otherwise, it returns B
. A || B
returns the value A
if A
can be coerced into true
; otherwise, it returns B
.
However, in practice, it is difficult to notice that &&
and ||
don’t consistently return boolean values. if
statements and loops execute when a condition evaluates to a truthy value, which means it does not need to be an actual boolean.
Complications with Non-Boolean Values Returned
For example, in a web application where users can be signed out and the user
object is null
, or they can be signed in and the user
object exists and has an isAdmin
property.
To verify if the current user is an administrator, checking if the user is authenticated is necessary. This means checking if the user
object is not null
. And then, you would check the isAdmin
property to see if it's truthy.
In the case that the user
object is not null
and the user
is an administrator, the user
object would be returned, rather than true
. The benefit is that this saves you the hassle of needing to check its existence and grabbing the data in separate operations. And in the case that the user
object is null
, null
will be returned, rather than false
.
However, this may be a problem if you have an isAdministrator
function which is meant to evaluate both conditions and return a boolean value because the prefix of the function is is
, thus concluding its purpose of returning true
or false
.
Convert Truthy/Falsy Value into a Proper Boolean
Option 1: Implicit Coercion
You can coerce a value into a boolean by using the logical NOT operator, which is the bang operator, and apply it twice.
Use Case Example
function isAdministrator(user) {
return !!(user && user.isAdmin);
}
Double Bang Operator
The first !
returns the value false
if the value can be coerced into true
. If the value cannot be coerced into true
, it will return true
. What is returned is always a proper boolean, however the truthiness of the value is reversed. And then the second !
undoes the reversal of the truthiness of the value.
Option 2: Explicit Coercion
You can explicitly coerce a value into a boolean by calling the Boolean
Function.
Use Case Example
function isAdministrator(user) {
return Boolean(user && user.isAdmin);
}
Switch Statements
Switch statements are another way to write a conditional, but it is less used. It takes in the variable and compares it to the value of each case
.
It is a type of conditional statement that evaluates an expression against multiple possible cases and executes one or more blocks of code depending on which cases match. Using switch statements is like using a conditional statement with numerous else if
blocks.
Related Keywords for Switch Statements
case
break
default
Syntax of switch
Statements
A switch
statement is always applied using switch () {}
.
Inside the parentheses is the expression to be tested. And inside the curly braces are the cases along with the code blocks that may be run:
switch(*variable name*) {
case *value*:
console.log(“”); // Code block executed on Truthy value
break;
case *value*:
console.log(“”);
break;
default: // Equivalent to: “else”
console.log(“”);
Each case
is evaluated by strict equality, and the cases are checked in chronological order. This example has 2 case
statements and default
is a fallback.
Here are the things that happen throughout the switch statement:
The expression is evaluated and the value is retrieved
The value of the first
case
is compared with the value of the expression. If there is a match, the code block within the case will run, and thebreak
keyword will end theswitch
block.If it is not matched with the first
case
, the code block within thatcase
will be overlooked, and the value of the nextcase
will be compared with the value of the expression.
If the value of that case matches the value of the expression, the code block will run and then exit out of the switch
block due to the break
statement.
If none of the values of the cases match the value of the expression, the code block after the default
statement will run.
Use Case Example
The following code block shows the month of the event with the getEvent()
method, which receives the id of the event as an argument and returns an object with all the event details. On this event object, there is a month
property, which is called, retrieving the number representing the month.
With a switch
statement, you can print the appropriate month name. The cases will be considered in chronological order and compared with the value of the expression.
When a matching case is discovered, the code block will run, and the break
statement at the end of that code block will stop the program from evaluating the rest of the cases and exit the switch statement:
// Set the month of the event to a variable, with 1 as January and 12 as December
const numMonth = getEvent(239).month;
switch (numMonth) {
case 1:
setMonth(‘January’);
break;
case 2:
setMonth(‘February’);
break;
case 3:
setMonth(‘March’);
break;
case 4:
setMonth(‘April’);
break;
case 5:
setMonth(‘May’);
break;
case 6:
setMonth(‘June’);
break;
case 7:
setMonth(‘July’);
break;
case 8:
setMonth(‘August’);
break;
case 9:
setMonth(‘September’);
break;
case 10:
setMonth(‘October’);
break;
case 11:
setMonth(‘November’);
break;
case 12:
setMonth(‘December’);
break;
default:
setMonth(getCurrentMonth());
}
If the month of the event is 3
, then the month
state will be set to the value of March
. And depending on the Event id passed through the getEvent() function, the month will be set to different strings.
The default
block is included at the end to be executed in case of an error where a number not corresponding 1-12 is passed.
Another use case could be to only set the value of month if the month is within the next three months in order to pull events happening soon in the future. This would mean that events would only be allowed to be in these months; and if the user input fell beyond these months, it would forcibly default to the current month.
If the break
keyword was not added to the end of each case code block, then none of the other case
statements would have evaluated to true
, but it would have been wasted energy sifting through the extra case
s.
To make your program faster and more efficient, include break
statements.
Switch Ranges
If you want to evaluate a range of values in a switch
statement, instead of just one, you can do so by setting the expression to true
, and then doing an operation within each case
statement specifying different conditions on each case
.
Since the match is auto-set to evaluate to true
, now the expression after case
will act like the condition after if
in if else
statements, and each case
will be evaluated chronologically until one condition is met or the switch
statement defaults.
You need to evaluate each case
to see if the expression evaluates to true
, run the appropriate code, and then break out of the switch
statement.
Use Case Example
// Set the time of the event
const time = 1800;
switch (true) {
case time >= 1800:
setEventTime(‘Evening’);
break;
case time >= 1200:
setEventTime(‘Afternoon’);
break;
case time >= 0:
setEventTime(‘Morning’);
break;
default:
setEventTime(‘Ambiguous’);
}
The expression in the parentheses to be evaluated is true
, meaning that any case
that evaluates to true
will be a match. In the code above, the eventTime
state will be set to ‘Evening’
.
Multiple Cases
If you want to have the same output for multiple different case
s, you can use more than one case
for each block of code.
Use Case Example
For example, if you want to match the time after 1800 and the time before 700 to 'Evening'
, you can do so like this:
// Get number corresponding to the time of the event
const time = getEvent(431).getTime();
switch (true) {
case time >= 1800:
case time <= 700:
setEventTime(‘Evening’);
break;
case time >= 1200:
setEventTime(‘Afternoon’);
break;
case time >= 0:
setEventTime(‘Morning’);
break;
default:
setEventTime(‘Ambiguous’);
}
The above code will result in an output setting the eventTime
state to the time of day depending on the conditions above.
Although 1800
would evaluate to true
for the other 2 case
s as well, the first match is for ‘Evening’
, so that will be set to the EventTime
variable.
The same can be applied to normal switch cases (not switch ranges).
switch
vs if else
Some similarities between switch
statements and if else
statements include the fact that they are both evaluated from top to bottom and also that the first true
returned is accepted.
switch
statements are advantageous due to their high readability and ability to evaluate the same variable at different values.
What are Loops?
Loops loop over the same block of code until a certain condition is met. Different types of loops provide different methods of curating the beginning and end points of a loop.
Loops will be written a lot. In every programming language, there are loops, control flow, & conditionals. And learning about loops is a part of software literacy.
Types of Loops
-
do while
loop -
while
loop -
for
loop -
for in
loop -
for of
loop -
forEach
loop
do while
Loops
The do while
loop runs a statement, and then repeats the statement(s) until a specified condition evaluates to false
.
Syntax of do while
Loops
do
statement
while (condition);
The statement is always run one time before the condition is evaluated. If you want to run many statements, use a block statement {}
to group them. If the condition is evaluated to true
, the statement runs again.
The condition is checked upon the conclusion of each execution. When the condition returns false
, the execution stops, and the program moves onto the code after the do while
loop.
Use Case Example
let i = 0;
do {
i += 1;
console.log(i);
} while (i < 20);
This do
loop iterates at least once and reiterates until i
is no longer less than 20
.
while
Loops
A while
loop continues executing its statements given that a specified condition evaluates to true
. It checks the condition at the start of each loop, and after code execution, it returns to check the condition. If the condition evaluates as true
, it runs the code block again.
Syntax of while
Loops
while (condition)
statement
The evaluation of the condition is done before the statement in the loop is run. And if the condition returns true
, then the statement
is run, and the condition
is evaluated again. If you want to run a series of statements, you can do so using a block statement {}
to group them.
If the condition evaluates to false
, then the statement(s) within the loop are not executed, and the program moves onto the next line of code after the loop.
Use Case Example
let a = 10;
while(a > 5) {
console.log (`a is now ${a}`);
a--;
}
This program goes back to the top of the loop with the new value, and then checks the condition in the ()
again. After the condition is met and the loop ends, the program moves onto the next line of code after the while
loop.
Use Case Example #2
let n = 0;
let x = 0;
while (n < 50) {
n++;
x += n;
}
This while
loop iterates as long as n
is less than 50. And during each iteration, the loop increments n
and adds that value to x
.
During the first execution, n
takes the value of 1
and x
takes the value of 1
. During the second execution, n
takes the value of 2
and x
takes the value of 3
. And during the third execution, n
takes the value of 3
and x
takes the value of 6
.
After the code has executed 50 times, the condition n < 50
returns false
, and then the loop ends.
Infinite Loop
Infinite loops are possible in both while
and do while
loops, as long as the condition is always evaluated to true
. This allows for the code block to run for an infinite number of times, which will lead to your application crashing.
It is important to ensure the condition in while
and do while
loops becomes false
at some point. You must modify the variable after each loop, which can be done by providing an incrementer or decrementer.
while
vs do while
The key difference between these two loops is the order of operations.
In a while
loop, the program first checks that the condition evaluates to true
, then runs the code block. In a do while
loop, first, the code block is run, and then the condition is evaluated to determine whether to rerun the code.
This means that do while
loops ensure the code block is run at least once; and it is possible for the code in a while
loop to never run.
while
vs for
The main advantage of using a while
loop is that it is flexible. This means that it can be made dynamic to the user input. This is useful when you do not know the number of times the loop needs to be run, or when you do not know the specific intent of the loop.
However, using a for
loop may be better for cases that are more specific. This means that it is useful for looping over arrays, looping over a specific number of lines, or when you know the specific number of times you want to run a code block.
for
Loops
A for
loop is similar to the while
loop, but the syntax is different. Nonetheless, the concepts are quite straightforward.
An advantage of for
loops is the fact that they are self-contained, which means that they cannot accidentally have an infinite loop the way that while
loops can. This is useful when iterating overall, or through a subset of items.
Syntax of for
Loops
for(*initial variable*; *condition*; *alteration*) {
*code block = directs logic of code: tells app how to make a decision*
}
Remember that semicolons are necessary within the parentheses ()
after for
and while
, but they are not necessary within the curly braces {}
after the parentheses ()
.
for
Loop Condition
There are 3 parts of a for
loop condition. First, the initialisation of a variable to use as part of the condition. Second, the actual condition that’ll evaluate true
or false
. And third, the incrementer to bring you closer to the end of the condition.
The incrementing will continue until the condition evaluates to false
, and at which point, the program moves onto the rest of the code.
Example Use Case
for(let a = 1; a < 5; a++) {
console.log(`a is now ${a}`);
}
The block of code will continue to run as long as the for
loop condition returns true
.
for in
Loops
for in
loop iterates a specified variable over all the keys inside an Object that are both user-defined and numeric indices.
For each distinct property, JavaScript runs the specified statements inside the for in
loop.
Syntax of for in
Loops
for (variable in object)
statement
Use Case Example
This function takes an argument of an object and the object’s name. Then, it iterates over all the parent object’s properties and returns a string that lists the property names and values:
function newProps(object, objectName) {
let result = ‘’;
for (const i in object) {
result += `${objectName}.${i} = ${obj[i]}<br>`;
}
result += ‘<hr>’;
return result;
}
For an Object named event
with properties month
and year
, result
returned would be:
event.month = September
event.year = 2022
Technically, user-defined properties (like custom properties or methods) can be assigned to arrays, so to ensure only numerically indexed array elements are accessed, rather than accessing both user-defined and numeric indices, use a for of
loop instead.
for in
loops can be used for both iterables and objects; nonetheless, using for in
loops on iterables should be avoided.
Object.keys()
vs for in
A for in
loop has the same utility as Object.keys()
. If you only want to return the keys of an object, Object.keys()
may be the way to go.
However, if you wish also to perform an operation for each element iterated through, for in
will be the faster way to do so, since using Object.keys()
and then a forEach()
requires passing a callback during every iteration.
for
vs for in
Both for
and for in
loops give access to the index of each element in an array and not the actual element value. This means that you still need to use the array name, followed by the given index, in order to find the element value.
Use Case Example
const arr = [‘Angeline’, ‘Sarah’, ‘Laura’]
for (let i = 0; i < arr.length; ++i) {
console.log(arr[i]);
}
for (let i in arr) {
console.log(arr[i]);
}
for of
Loops
for of
statements create a loop that iterates over iterable objects. It will invoke a custom iteration hook with statements to be executed for the value of each distinct property.
The difference between a for of
loop and a for in
loop is that a for of
loop iterates over property values, instead of names.
for of
loops (without additional aid) cannot be used to iterate over an object, it can only be used to iterate over iterable objects.
When to use for of
loops
for of
loops are the best way to iterate over an array in JavaScript because they are more concise than the conventional for
loop and also does not have as many edge cases as for in
and forEach()
loops.
However, for of
loops do take extra work to access element indices, and you cannot chain them like you can do with forEach()
loops.
Syntax of for of
Loops
for (const element of array) {
console.log(element)
// Each array element is being assigned to the variable named “element” during each iteration until all the elements have been iterated upon
}
The first part within the parentheses before of
is a variable declaration (with anything before the =
operator), which can be done with let
var
or const
.
const
can be used so long as the variable is not reassigned within the code block. Between iterations, the function context is considered new, so it is okay to use const
.
If the elements within the iterable are objects, you can also destructure the object property like so: for (event.date of events)
.
for of
vs for in
There are two important factors that differ in terms of for of
and for in
loops:
First is what part of each element they iterate over and return. for in
loops iterate over the keys of each element, while for of
loops iterate over the values of each element.
Second is what kind of elements they include in their operations. for of
loops only iterate through elements with numeric array index keys, so they only work for array-type objects.
for in
loops do not discriminate based on the origins of keys, and include all elements, with either numeric array indices as keys and user-generated elements with string keys.
Comparison Example
const arr = [1, 2, 3];
arr.greeting = ‘good afternoon’;
// for of
for (const i of arr) {
console.log(i);
}
// Prints: “1” “2” “3”
// for in
for (const i in arr) {
console.log(i);
}
// Prints: “0” “1” “2” “greeting”
If you wish to return the values of elements including those with user-generated string keys, you can do so by using a for in
loop with bracket notation. All keys, including user-generated ones, can be passed inside the brackets after the object name, like so:
const arr = [1, 2, 3];
arr.greeting = “good afternoon”;
for (const i in arr) {
console.log(arr[i])
} // Prints: “1” “2” “3” “good afternoon”
It seems there is no premeditated way to return only the keys that are numeric array index keys.
Object.entries()
Both for of
and for in
loops can also be used with destructuring. For example, they can both simultaneously loop over keys and values of an object with Object.entries()
.
With the use of Object.entries()
, an array (with numeric indices as keys) is created from an object (previously array or non-array). This means that by replacing the arr
with Object.entries(arr)
, even an object with user-generated string keys can be used with for of
, like so:
// for of
const obj = { angeline: 10, laura: 20 };
for (const [key, val] of Object.entries(obj)) {
console.log(key, val);
}
// Prints:
// “angeline” 10
// “laura” 20
forEach
Loops
forEach
loops are useful for iterating through all the items in a collection. It is read-only, meaning it cannot modify items as they are being iterated through.
When to Use forEach
Loops
A good rule of thumb is to use forEach
sparingly because it comes with many edge cases. However, there are still many cases where it can be used to make code more concise.
Syntax of forEach
Loops
const guests = [‘Angeline’, ‘Laura’, ‘Sarah’];
guests.forEach(guest => console.log(guest));
The forEach
loop takes a callback function that is used on each element within the array. The callback function takes a mandatory current value parameter, and optionally, the index and the array object.
forEach
vs for of
One similarity between forEach
and for of
is the fact that they both access the array element value itself. One difference is that the forEach
loop can access both the value and the index, which can be passed in as the second parameter.
Comparison Example
arr.forEach((v, i) => console.log(v));
for (const v of arr) {
console.log(v);
}
One case where you would choose to use for of
instead of forEach
is if you want to ensure prevention of “holes” in your user data, which can result from empty array elements.
Labeled Statements
You can add a label
to a statement to act as an identifier you can reference elsewhere in your program.
When to Use Labeled Statements
A label is useful for identifying a loop, and then to use break
or continue
statements to show if the program should interrupt the loop or continue its execution.
Syntax of Labeled Statements
label: // This can be any JS identifier, excluding reserved words
statement // Can be any statement
Use Case Example
angelineLoop:
while (isAngeline) {
doSomething();
}
Non-Numeric Properties
Since JavaScript arrays are objects, it is possible to also add string properties to an array, not just the number indices.
for of
, for
and forEach
loops all ignore non-numeric properties and print out only numeric properties; however, for in
loops will print out both numeric and non-numeric properties.
This means that by default, it is best to use for of
loops on arrays with only numeric properties.
Empty Elements
You are allowed to have empty elements in a JavaScript array, but the 4 looping constructs will handle empty elements differently. for in
and forEach
loops will skip the empty element; while for
and for of
loops do not skip the empty element, and instead prints out undefined
in its place.
Use Case Example
const arr = [‘Angeline’, , ‘Laura’];
arr.length; // 3
for (let i = 0; i < arr.length; ++i) {
console.log(arr[i]); // Prints “Angeline, undefined, Laura”
}
arr.forEach(v => console.log(v)); // Prints “Angeline, Laura”
for (let i in arr) {
console.log(arr[i]); // Prints “Angeline, Laura”
}
for (const v of arr) {
console.log(v); // Prints “Angeline, undefined, Laura”
}
This behaviour only occurs when there is literally an empty array element. If the array element has a value of undefined
, the 4 looping constructs will universally print “Angeline, undefined, Laura”
.
Add Empty Array Element
If an element at a larger index than the logical subsequent is added, the intermediary indices in the array will be filled with empty elements.
Use Case Example
const arr = [“Angeline”, “Sarah”, “Laura”];
arr[5] = “Maya”;
// Equivalent to [“Angeline”, “Sarah”, “Laura”, , “Maya”]
forEach()
and for in
loops skip empty elements in the array. for
and for of
loops do not.
Interaction with JSON
However, empty elements are not supported in JSON, and will be marked as a SyntaxError: Unexpected token
. Thus, it is rare that empty elements will be used.
Likely, null
will be used in place of any empty elements. This means that the behaviour of forEach()
and for in
loops when treating empty elements will rarely cause a practical issue.
When for…in
and forEach()
loops skip empty elements in an array, this behaviour is called “holes”. Any “holes” should likely be treated as having a value of undefined
.
It is possible to disallow using forEach()
in order to prevent cases of holes. You can write a .eslintrc.yml
file with the following content:
parserOptions:
ecmaVersion: 2018
rules:
no-restricted-syntax:
- error
- selector: CallExpression[callee.property.name="forEach"]
message: Do not use `forEach()`, use `for/of` instead
Function Context
for
, for in
and for of
loops retain the outside scope’s value of this
. And the forEach()
callback will have a different this
unless you use an array function.
If you want to ensure that all 4 types of loops access the same value for this
, you need to enforce a rule to only allow forEach()
loops to be used with arrow functions. This can be done through the no-arrow-callback
ESLint rule to require arrow functions for all callbacks that don’t use this
.
Async/Await Generators
forEach()
loops do not precisely work with async/await or generators. Inside an async
function that has a forEach()
callback function, you cannot use an await
, nor can you use a yield
.
Syntax errors will be thrown if code like below is written:
async function run() {
const arr = [ ‘Angeline’, ‘Sarah’, ‘Laura’];
arr.forEach(el => {
// SyntaxError
await new Promise(resolve => setTimeout(resolve, 1000));
console.log(el);
});
}
function* run() {
const arr = [‘Angeline’, ‘Sarah’, ‘Laura’];
arr.forEach(el => {
yield new Promise(resolve => setTimeout(resolve, 1000));
console.log(el);
});
}
However, the 2 code examples do work with for of
loops, like this:
async function asyncFn() {
const arr = [‘Angeline’, ‘Sarah’, ‘Laura’’];
for (const el of arr) {
await new Promise(resolve => setTimeout(resolve, 1000));
console.log(el);
}
}
function* generatorFn() {
const arr = [‘Angeline’, ‘Sarah’, ‘Laura’];
for (const el of arr) {
yield new Promise(resolve => setTimeout(resolve, 1000));
console.log(el);
}
}
When using async/await or generators, forEach()
is syntactic sugar, so it should be used sparingly and not for everything.
How to Control Loops
There are 2 control flow statements that can be used as operators to further manipulate the execution of code within loops:
-
break
statements -
continue
statements
These can be applied to switch
statements or any of the loops (excluding forEach
) to alter the normal control flow of the loop. Where a statement is exited prematurely, clean-up will be performed with the return()
method of the iterator.
break
Statements
The purpose of break
statements is to terminate a loop, a switch
statement, or it can be used with a labeled statement.
Syntax of break
Statement
break;
break label;
Example Use Case
for (let i = 0; i < events.length; i++) {
if (events[i] === ‘party’) {
break;
}
}
This iterates through the elements in an array until the program finds the index of an element whose value is ‘party’
.
Using break
without a Label
If you use a break
statement without a label, you will immediately stop the innermost enclosing while
, do while
, for
or switch
and move onto the next line of code after the while
, do while
, for
or switch
statement.
Using break
with a Label
If you use a break
statement with a label, you will stop the specified labeled statement and move onto the line of case after the break
statement.
Break to a Label
let x = 0;
let z = 0;
labelCancelLoops: while (true) {
console.log(‘Outer loops: ’, x);
x += 1;
z = 1;
while (true) {
console.log(‘Inner loops: ’, z);
z += 1;
if (z === 10 && x === 10) {
break labelCancelLoops;
} else if (z === 10) {
break;
}
}
}
continue
Statements
A continue
statement can be applied to restart a while
, do while
, for
loop or label
statement.
Syntax of continue
Statement
continue;
continue label;
continue
will end the current iteration (leaving remaining code in the block untouched), but it will go back to the start of the loop at the condition and run the loop again. It will not completely break out of the loop as a whole onto the next line of code, it just breaks out of the current iteration of the loop.
Use Case Example
Here is a while
loop with a continue
statement that runs when the value of i
is 5
. n
takes on the values 1
, 3
, 6
, 10
, 16
, 23
, 31
, 40
, 50
:
let i = 0;
let n = 0;
while (i < 10) {
i++;
if (i === 5) {
continue;
}
n += i;
console.log(n);
}
//1,3,6,10,16,23,21,3,0,40
If continue
is removed, the loop would instead print: 1,3,6,10,15,21,28,36,45,55
.
Use Case Example #2
Here is a while
loop labeled checkxandy
includes another while loop labeled checky
. If continue
is encountered, the program ends the current iteration of checky
and starts the next iteration:
let x = 0;
let y = 10;
checkxandy: while (x < 4) {
console.log(x);
x += 1;
checky: while (y > 4) {
console.log(y);
y -= 1;
if ((y % 2) === 0) {
continue checky;
}
console.log(y, ‘ is odd.’);
}
console.log(‘x = ‘, x);
console.log(‘y = ’, y);
}
Every time continue
is encountered, checky
reiterates until its condition returns false
. When false
is returned, the remainder of checkxandy
is run and checkxandy
reiterates until its condition returns false
. When false
is returned from checkxandy
, the program continues onto next line of code after checkxandy
.
If continue
had a label of checkxandy
, the program would continue at top of checkxandy
loop.
continue
without Label
Using continue
without a label will end the current iteration of the innermost enclosing while
, do while
, or for
statement and continue the execution of the loop with the next iteration.
continue
with Label
Using continue
with a label will apply it to the looping statement identified with that label.
continue
vs break
continue
does not end the loop entirely. In a while
loop, continue
will lead the program to jump back to the while
loop’s condition. And in a for
loop, continue
will lead the program to jump to the “increment-expression”.
Conclusion
In this article, we when over what control flow is and different ways we can manipulate control flow in JavaScript through conditionals and loops.
A wide range of use cases were covered with the functionality of if else
, ternary operators, and switch
statements, in order to alter code blocks executed during runtime conditionally. We also discussed the varying flexibility of using while
loops and for
loops.
To explore these topics in more detail, I've added some useful links below.
Happy learning!
Resources for Further Exploration
Conditionals - Learn: JavaScript.com
Conditional (ternary) operator: MDN Web Docs
Expressions and operators: MDN Web Docs
The && and
|| Operators in JavaScript: Marius Schulz
JavaScript for… of Loop: Programix
function*: MDN Web Docs
this: MDN Web Docs
Learn ES6 The Dope Way Part II: Arrow functions and the ‘this’ keyword
For vs forEach() vs for/in vs for/of in JavaScript
Loops and iteration: MDN Web Docs
How To Use the Switch Statement in JavaScript: DigitalOcean
Top comments (1)
Сongratulations 🥳! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up 👍