Control Flow in JavaScript

Learning Objectives
Students will be able to: |
---|
Use conditional expressions with branching & looping |
Identify what is "truthy" and "falsy" in JavaScript |
Understand what the logical || and && operators return |
Use the if...else statement to perform branching |
Use the for & while statements to perform looping |
Road Map
- What is Control Flow?
- Conditional Expressions
- The Logical
||
(or) and&&
(and) Operators - Branching
- Looping
- Number Guessing Game Code-Along
- Essential Questions
- Further Study
Videos
Lesson Setup
-
We will use replit.com to work with the concepts and complete the exercises in this lesson - create a new Node.js-based Repl.
-
Name the Repl something like "JS Control Flow"
-
Open a tab in your browser and copy/paste this snippet into the address bar for a convenient note pad:
data:text/html, <html contenteditable style="font-family: 'Lucida Console', Monaco">
Bookmark it too for future use!
1. What is Control Flow?
"The execution sequence of instructions in a program determined at run time with the use of control structures"
Basic Types of Control Flow
-
Sequence:
let name = prompt('Enter your name: ');
let city = prompt('What city do you live in? ');
Statements execute one at a time in sequence.
-
Branching:
// ↓--------- ↓ -> conditional expression
if (points > 100) {
console.log('Congrats!');
} else {
console.log('Keep playing!');
}
Different code paths/branches are executed based upon a conditional expression.
-
Looping:
// ↓--------- ↓ -> conditional expression
while (points < 100) {
let move = getPlayerMove();
points += getPoints(move);
}
Code is repeatedly executed while a condition is truthy.
2. Conditional Expressions
As we see above, both branching and looping depend upon a conditional expression.
Examples of conditional expressions:
(word === secretWord)
(numWrongGuesses > MAX_WRONG_GUESSES)
(winner)
A conditional expression, like any JS expression, is a piece of code that evaluates to a single value/thing (object) - and every single value/thing is truthy or falsy.
Let's take a look at what values/things are considered to be truthy and falsy...
What is true
/truthy & What is false
/falsy?
A "truthy" value is a value that is considered to be true
when used in a conditional expression such as that used in an if
statement. Similarly, a "falsy" value is a value that is considered to be false
.
Why this truthy and falsy business? Why not just true
and false
?
Answer: The ability to use non-boolean expressions as booleans (true
or false
) allows us to write code that is more concise.
To test what is truthy and what is falsy, let's type the following code into replit:
if (true) {
console.log('truthy!');
} else {
console.log('falsy!');
}
❓ As written above, clicking Replit's [Run] button will always print what to the console?
'truthy!'
because the if
statement's conditional expression has the value true
Now we can easily test expressions by typing it in the place of true
...
For example, the number 3
, is considered to be truthy - let's try it and see.
Everything in JS is truthy except for the following six things
false
(of course)- The
null
data type - The
undefined
data type - The empty string
''
- The number
0
(zero) NaN
(special number)
If it's not in the above list, it's truthy!
The Not Operator
The not operator (!
), also known as the "bang" operator, "flips" a true/truthy expression to the boolean value of false
, and vice-versa. For example:
!false === true // true
!null === true // true
!3 === false // true
!'' === true // true
A double !
operator is a great way to force an expression into its actual boolean value of true
or false
:
console.log(!!3); // outputs true
Boolean Logic (Comparison Operators)
Comparison Operators are used to compare the values of left and right operands which can be variables, literal values, object properties, etc.:
Operator | Purpose |
---|---|
=== | strict equality - best practice |
== | performs type conversion (called coercion) - its use is not recommended |
!== | strict inequality |
!= | inequality |
< | less than |
> | greater than |
<= | less than or equal |
>= | greater than or equal |
In your pre-work you saw a for
loop use the <
comparison operator to ensure that the looping variable, i
, didn't exceed an array's upper bound...
for (let i = 0; i < array.length; i++) {
// statement block
}
❓ Review Questions - Conditional Expressions (1 min)
(1) Is the value of 0
(zero) truthy or falsy?
0
(zero) truthy or falsy?falsy
(2) Is an empty string truthy or falsy?
falsy
(3) Is an "empty" object (an object with no properties) truthy or falsy?
truthy
(4) What the expression !!0
evaluate to?
!!0
evaluate to?false
3. The Logical ||
(or) and &&
(and) Operators
The logical operators ||
and &&
can be used to combine multiple conditional expressions like this:
if (num < 1 || num > 10) {
console.log('Number is not between 1 and 10 inclusive');
}
However, because of the fact that they always return either their left or right operands they can be used in other ways as well...
The logical ||
(OR) operator always returns the first operand if it is truthy, otherwise return the second operand:
'hello' || 'goodbye' // evaluates to 'hello'
0 || null // evaluates to null
The logical &&
(AND) operator always returns the first operand if it is falsy, otherwise return the second operand:
'hello' && 'goodbye' // evaluates to 'goodbye'
0 && null // evaluates to 0
💪 You Do - Logical Operators (1 min)
Jot down what each of following expressions evaluate to:
(1) 'cat' || 'dog'
'cat'
(2) false || true
true
(3) true && false
false
(4) false && true
false
(5) 10 || 'ten'
10
(6) 10 && 'ten'
'ten'
Note that if the expression results in the first operand being returned, JS won't even evaluate the second operand. This "short circuiting" as it's called, can be used in interesting ways...
💪 You Do - Advanced Use of Logical Operators (1 min)
Analyze the following two code snippets and do your best to predict what will happen based upon what values might be returned from the functions:
winner = checkWinAcross() || checkWinVertical();
View explanation for above snippet
If checkWinAcross()
returns a truthy value, that truthy value will be assigned to winner
, otherwise, winner
will be assigned whatever value is returned by checkWinVertical()
winner && handleWinner();
View explanation for above snippet
The handleWinner()
function will run only if winner
holds a truthy value
4. Branching
As you saw in the pre-work, the if..else
statement allows us to conditionally execute code.
The if
Statement (Single Path)
// Assume char holds a character inputted by the user
if ('aeiou'.includes(char)) {
console.log('char is a vowel!');
}
Again, the conditional expression must be surrounded by parenthesis.
If you have only a single statement that needs to execute, you can write that statement without using curly braces (used to define a block of statements):
// This code is functionally identical to the above code
if ('aeiou'.includes(char)) console.log('char is a vowel!');
The if...else
Statement (Dual Path)
When you verbalize logic using language like:
"If something is true do this, otherwise, do that"
The if
/else
statement is your go to:
// Assume winner holds true or false
if (winner) {
console.log('Game has been won!');
} else {
console.log('Keep playing!');
}
The if...else...if
Statement (Three or More Paths)
If you have three or more code paths use if
with as many else if
clauses as necessary and optionally a final else
:
if (guessNum < secretNum) {
console.log('Guess higher!');
} else if (guessNum > secretNum) {
console.log('Guess lower!');
} else {
console.log('You guessed the number!');
}
FYI, a final else
is not mandatory and can be skipped if your app's logic doesn't need it.
👉 You Do - Branching (5 mins)
Write the if...else..if
statement that console.logs the following based upon the value of a variable named color
:
- If the value is
'green'
, log'Go'
- If the value is
'yellow'
, log'Slow'
- If the value is
'red'
, log'Stop'
- If the value is anything else, log
'Whatever'
Hint: Don't forget to declare and initialize a variable named
color
BEFORE theif...else...if
.
5. Looping
Looping statements provide us with the ability to execute a block of code multiple times while a conditional expression remains truthy.
We'll take a look at these statements:
for
: Used to iterate a known number of timeswhile
: Used to iterate an undetermined number of times
Looping - for
loop
for
loops are commonly used to run a block of code a certain number of times:
let upTo = prompt('Iterate from 1 to ?');
upTo = parseInt(upTo);
for (let n = 1; n <= upTo; n++) {
console.log('Current number: ', n);
}
Notice the for
loop has three parts after the for
keyword:
- The initializer which runs only once before looping begins. It is used to declare and initialize a looping variable.
- The condition which will be evaluated before each loop. If truthy, the code block will execute.
- The last part will execute after each loop and is typically used to increment or decrement the looping variable by one or more units.
Looping - while
Statement
The while
loop is the go to when the number of iterations is unknown and has the following syntax:
while (/* conditional expression */) {
// statement block
}
❓ What determines when the looping will end?
When the conditional expression evaluates to a falsy value
Beware of infinite loops! If the conditional expression fails to sooner or later evaluate to a
falsy
value, the loop will continue endlessly. This often results in the computer being unresponsive. Another way to exit the loop is with the break statement (see the Further Study section).
6. Number Guessing Game Code-Along
Let's use branching and looping to code a simple number guessing game!
Before coding programs it's often beneficial to pseudocode, i.e., write down the logic/steps in plain language that are necessary to solve the problem at hand...
// 1. Generate a random secret number
// 2. Declare a variable to hold the player's guess
// 3. Loop while the player's guess is not correct
// 3.1. Prompt for the player's guess
// 3.2. Convert the player's input into a number
// 3.3. If the guess is lower or higher than the secret
// number, print a message that informs the player as such
// 4. Print a message congratulating the player
Let's copy/paste the above pseudocode and use it as our guide as we implement the code.
For reference, here's a potential solution...
// 1. Generate a random secret number
// Using a "constant" helps document the code
// and make it more maintainable
const MAX_NUM = 100;
// Adding 1 makes the number one-based instead of zero-based
const secretNum = Math.floor(Math.random() * MAX_NUM) + 1;
// 2. Declare a variable to hold the player's guess
let guessNum;
// 3. Loop while the player's guess is not correct
while (guessNum !== secretNum) {
// 3.1. Prompt for the player's guess
guessNum = prompt('Enter your guess: ');
// 3.2. Convert the player's input into a number
guessNum = parseInt(guessNum);
// It's also possible to do the above on with a single line
// guessNum = parseInt(prompt('Enter your guess: '));
// 3.3. If the guess is lower or higher than the secret
// number, print a message that informs the player as such
if (guessNum < secretNum) {
console.log('Your guess was too low - try again!');
} else if (guessNum > secretNum) {
console.log('Your guess was too high - try again!');
}
}
// 4. Print a message congratulating the player
console.log('Congrats, you guessed the secret number!');
Bonus Challenge
As a stretch bonus challenge, consider adding the following features on your own:
- Let the player input the maximum value of the secret number.
- Keep track of the number of wrong guesses and print a message if that number exceeds a predetermined maximum amount.
7. ❓ Essential Questions
(1) The three primary types of control flow are:
A) Sequence
B)
C)
A) Sequence
B)
C)
A) Sequence B) Branching C) Looping
(2) What does the expression 'happy' || 'sad'
return?
'happy' || 'sad'
return?'happy'
(3) If we don't know in advance how many times we need to iterate, we should use a ___________ loop.
while
loop
8. Further Study
Ternary Operator
The ternary operator is ideal when you need to return one of two values depending upon a condition:
let message = score > 100 ? "You rock!" : "Keep trying!";
The above one line of code replaces this code:
let message;
if (score > 100) {
message = "You rock!";
} else {
message = "Keep trying!";
}
A ternary can also be used to evaluate one of two expressions, so you can actually run a method if you'd like:
score > 100 ? gameWinner() : gameLoop();
Note that unlike with
if
andwhile
, ternary expressions do not require the conditional expression to be within parenthesis.
switch
Statement
Look into using the switch statement instead of if...else
if you have more than three code paths and your conditionals always check the same variable.
do
...while
You may choose to use the do...while
statement instead of while
to force the code block to always execute at least once. This is rarely used, but useful to recognize when reading other developer's code.
let num = 0;
do {
console.log(num + ' is even');
num += 2;
} while (num <= 10);
Do you see why the code block will always run at least once?
Again, beware of infinite loops!
The break
& continue
Statements
The break statement is used to immediately exit a while
or for
loop. For example:
let word = '';
let words = [];
while (true) {
word = prompt('Enter a word ("end" to quit)');
if (word === 'end') break;
words.push(word);
console.log("You've entered: " + words.join(', '));
}
Note again how the
if
statement does not require braces since there's a single statement to execute.
The continue statement skips remaining code in the current iteration and returns to the top of the while
or for
loop.