Control Structures in Javascript: Steering Your Code Like a Pro 🚦


Every program makes decisions — it checks conditions, repeats tasks, and determines the next course of action. 🤔
In Javascript, control structures are the tools that make all this possible.
Without this decision-making🚦, our code would just execute line by line, completely ignoring the changing conditions of real-world problems.
That's where control structures come in. They're the traffic controllers of Javascript — telling our program when to stop, when to go, and when to loop back around.
In this article, we'll explore conditional statements and loops — an essential ingredient of Javascript.
We'll cover what they are, why we use them when to use each one, common gotchas, and tips for writing clean, efficient code.
(🤠Eh!, We'll save some tricky topics like truthy/falsy values and deep Boolean logic for the following article.)
What Are Control Structures?
Control structures are special parts of Javascript that determine the flow of execution. They answer questions like:
Should we run this block of code? 🤔
Should we skip to another block? 🤯
Should we repeat something until a specific condition is met? 🥱
By the way, in Javascript, a block of code is the part inside curly braces { ... }
— it groups statements together so they run as one unit.
Without control structures, every script would be a boring, predictable list of instructions.
But with them, we can handle user input, make decisions, and repeat tasks dynamically.
Think of them as the decision-makers and repeaters in our programs — making our code smarter and more responsive.
Conditional Statements: Deciding What to Do
if
Statements
The simplest and most common control structure in Javascript is the if
statement.
The if
statement checks whether a condition is true
and, if it is, runs the code inside its block.
It's the simplest way to tell our program:
"Only do this if the condition holds true."
let isLoggedIn = true;
if (isLoggedIn) {
console.log("Welcome back!");
}
Here, the message prints only if isLoggedIn
is true
. If it's false
, Javascript simply skips the block.
Whenever we want our program to do something only under certain conditions, if
is our go-to.
We use it for clear, straightforward checks — things like user authentication, input validation, or enabling a feature only when the user has the proper access.
But, like all tools, it has limits:
Nested
if
s can turn ugly fast — when we're 3–4 levels deep, we end up with the dreaded "pyramid of doom." That's our sign to refactor or use a better structure, such as aswitch
or early returns.Gotcha: Make sure the condition is correct. A single typo — writing
=
(assignment) instead of==
or===
— can make the condition alwaystrue
(orfalse
), causing unexpected behaviour.
if…else
Statement
Adds an "otherwise" option:
"Do this if the condition is true, otherwise do that."
let isLoggedIn = false;
if (isLoggedIn) {
console.log("Welcome back, Luna!");
} else {
console.log("Please log in first.");
}
If isLoggedIn
is false
, Javascript runs the else block.
When you want to handle both true
and false
conditions — make use of the else
block.
if…else if…else
Chain
When we have multiple possibilities, we can chain else if
blocks.
let score = 85;
if (score >= 90) {
console.log("Grade: A");
} else if (score >= 75) {
console.log("Grade: B");
} else if (score >= 50) {
console.log("Grade: C");
} else {
console.log("Grade: F");
}
Here, the score
is 85
, so Javascript prints "Grade: B
" and stops checking any further.
With an if...else if...else
chain, Javascript checks each condition in order, top to bottom.
The moment one condition matches, it runs that block and skips the rest.
This means we can optimise performance a bit by putting the most likely conditions first.
Always remember:
The
else
block goes last — it's the fallback that runs only if none of the above conditions matches.Too many
else if
branches can make our code harder to read. When we're juggling 5–6 different cases, aswitch
statement might be a cleaner alternative.
Before we dive into the switch
statement, let's meet the deal-breakers of loops: the jump statements — break
and continue
.
break
& continue.
break
→ Think of it as hitting the emergency stop button 🚨. It immediately ends the loop (or the nearest enclosing block) and jumps out, ignoring everything left inside it.
for (let i = 0; i < 10; i++) {
if (i === 5) break; // stop looping when i hits 5
console.log(i);
}
// Output: 0, 1, 2, 3, 4
Here, as soon as i
becomes 5
, Javascript bails out of the loop completely.
continue
→ Think of it as saying "skip this one, move on!". Instead of ending the loop, Javascript skips the current iteration and moves to the next.
for (let i = 0; i < 10; i++) {
if (i === 5) continue; // skip this iteration when i hits 5
console.log(i);
}
// Output: 0, 1, 2, 3, 4, 6, 7, 8, 9
Here, when i
is 5
, the loop jumps straight to the next round, ignoring the console.log(i)
line.
When do we use them?
Use
break
when you've already found what you were looking for and want to exit early (e.g., searching in an array).Use
continue
when you don't care about the current item and want to skip, but keep the loop going.
⚠️ Gotcha: Overusing them can make loops hard to read. Think of them as shortcuts, not your main road.
switch
Statement
When we're checking a single value against many options, switch
can be a lifesaver. It's often cleaner than a dozen else ifs
.
The previous if...else if...else
can be written as below,
let score = 85;
switch (score) {
case (score >= 90):
console.log("Grade: A");
break;
case (score >= 75):
console.log("Grade: B");
break;
case (score >= 50):
console.log("Grade: C");
break;
default:
console.log("Grade: D");
}
Another example,
let fruit = "apple";
switch (fruit) {
case "apple":
console.log("Apples are $1.50 per lb.");
break;
case "banana":
console.log("Bananas are $0.60 per lb.");
break;
default:
console.log("Sorry, we don’t have that fruit.");
}
Always remember:
break
stops theswitch
after a match. Without it, cases "fall through" into the next block.default
runs when none of the cases matches.
It makes our intent clearer when comparing one value against multiple possibilities. Also, it is easier to maintain when adding or reordering options.
It works best when we have many fixed options for a single value (such as command menus, API response codes, or configuration switches).
⚠️ Gotchas:
Using
switch
for ranges or complex conditions (stick toif/else
in those cases).Forgetting the
break
keyword leads to bugs where multiple cases execute unintentionally.
Optimisation tip:
Group cases that share the same behaviour to reduce duplication:
switch (day) {
case "Saturday":
case "Sunday":
console.log("Weekend vibes! 🎉");
break;
default:
console.log("Work day!");
}
Ternary Operator (?:)
We've already explored this in our operators article, but let's recap. The ternary operator is a shorthand for if...else
, perfect for simple assignments:
let isMember = true;
let discount = isMember ? "10%" : "0%";
console.log(discount); // "10%"
It is quick, precise, and single-line decisions.
Avoid nesting ternary operators; they become unreadable fast.
Loops: Repeating Tasks Efficiently
Loops allow us to repeat a block of code multiple times without having to write it over and over.
for
Loop
The for
loop is the classic choice for executing a specific task a certain number of times.
for (let i = 1; i <= 5; i++) {
console.log(`Iteration ${i}`);
}
let i = 1;
→ initialiation: we start our counteri
at1
.i <= 5;
→ condition: keep looping as long asi
is5
or less.i++
→ increment: after each loop, increasei
by1
.
Here's what happens step by step:
The loop creates a variable
i
and sets it to1
.It checks the condition — is
i <= 5
? Yes, so the block inside{}
runs, printingIteration 1
.After running the block, it increments
i
to2
and rechecks the condition — isi <= 5
? Yes, so the block runs again.This repeats until
i
becomes6
, the condition fails, and the loop stops.
We reach for a for
loop when we know exactly how many times we need to repeat something — like counting, iterating through arrays, or running code a set number of times.
Gotchas ⚠️
Infinite loops: Forgetting to update i
can trap us forever:
for (let i = 0; i >= 0; ) {
console.log("Oops!"); // Never ends
}
Off-by-one errors: Starting or ending at the wrong number is super common. Double-check your start and end conditions.
while
Loop
A while
loop keeps running as long as its condition remains true
.
let count = 0;
while (count < 3) {
console.log(`Count: ${count}`);
count++;
}
Here's what's happening step by step:
We check the condition: is
count < 3
?If
true
, Javascript runs the block inside{}
and prints thecount
.After printing,
count++
increments the value ofcount
.Javascript rechecks the condition, and the cycle continues until
count
reaches3
.Once the
count
is no longer less than3
, the loop stops.
We use a while loop when we don't know in advance how many times the code should run — for example, waiting for some input to change or polling data from an API.
Gotchas ⚠️
Infinite loops happen easily if the condition never turns false
:
while (true) {
console.log("Never-ending story…");
}
Always ensure your loop has an exit condition — something that eventually stops it.
do…while
Loop
A do…while
loop is like while
, but it always runs at least once, even if the condition fails on the first check.
let number;
do {
number = Math.floor(Math.random() * 10);
console.log(number);
} while (number !== 5);
Javascript runs the block first, generates a random number, and prints it.
After that, it checks the condition
number !== 5
.If the
number
isn't5
, the loop continues; otherwise, it stops.
Best for cases where we always need at least one run before checking the condition — such as obtaining user input or rolling a dice until we hit a specific number.
Gotcha ⚠️
Be careful not to create an infinite loop when the exit condition is very rare or never met.
for…of
Loop
Introduced in ES6 (2015), a for…of
loop makes iterating over values of iterable objects (arrays, strings, Maps, Sets, etc.) clean and straightforward.
let users = ["Luna", "Marco", "SK"];
for (const user of users) {
console.log(user);
}
user
takes each value from theusers
array one by one.Cleaner than a
for
loop when we just need values and not indexes.
Where for…of
shines:
Arrays: for (const item of myArray)
Strings: for (const char of myString)
Maps: for (const [key, value] of myMap)
Sets: for (const item of mySet)
NodeLists: (in the DOM): for (const node of myNodeList)
Why we love it:
Clean syntax, direct access to values, and it works with any iterable.
Supports
break
andcontinue
for…in
Loop
A for…in
loop iterates over the keys (property names) of an object.
const person = {
firstName: "John",
lastName: "Doe",
age: 30
};
for (let key in person) {
console.log(`${key}: ${person[key]}`);
}
On each iteration, key
holds the property name, and we can access its value using person[key]
. We'll dive deep into objects in a later article, so think of this as a quick teaser.
Best for looping through all the property names of plain objects.
Gotchas with arrays:
Although for…in
technically works on arrays, it loops over indexes as strings and can even pick up inherited properties.
For actual array values, stick with for…of
or forEach()
— they're cleaner and safer.
Control structures are the mechanisms by which we instruct our programs to make decisions and repeat tasks. With conditional statements, we instruct Javascript on how to behave in various situations, and with loops, we automate repetitive tasks.
Knowing these will enable us to write cleaner, smarter, and more maintainable code.
We're still laying the foundation for condition logic — truthy and falsy values are up next. Stay tuned! 🚀
Subscribe to my newsletter
Read articles from Sangy K directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Sangy K
Sangy K
An Introvert Coder | Trying to be a Full-stack Developer | A Wannabe Content Creator