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...elsestatement to perform branching | 
| Use the for&whilestatements 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 nulldata type
- The undefineddata 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
colorBEFORE 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 times
- while: 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
falsyvalue, 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
ifandwhile, 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
ifstatement 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.