Progress pill
Basic JavaScript

Blocks and control flow

JavaScript and NodeJS Fundamentals

Blocks and control flow

  • The global scope
  • Blocks and local scope
  • If, else
  • While, break, continue
  • For ... of ...
  • For ... in ...
  • Bounded loops
  • Block labels
So far, we’ve mostly written lines of code that run one after the other.
But when we code, we can control the order of execution of it.
This is called control flow.
Let’s start with understanding blocks and scope.

The global scope

Every variable we declare exists in a scope, which means the region of the code where the variable is known.
If you declare a variable outside of any block, it exists in the global scope.
const color = "blue" console.log(color)
This variable color is in the global scope, so it can be accessed from anywhere in the file.
If you add more lines:
const color = "blue" console.log(color) const size = "large" console.log(color) console.log(size)
Both color and size are global variables. They are available everywhere in the file.
But what happens inside a block?

Blocks and local scope

A block is a piece of code surrounded by curly braces {}.
Variables declared with let or const inside a block exist only inside that block.
{ const message = "inside block" console.log(message) }
This prints:
inside block
But if you try this:
{ const message = "inside block" } console.log(message) // Error!
JavaScript will give you an error like:
ReferenceError: message is not defined
That’s because message was declared inside the block and doesn’t exist outside of it.
This means we can use blocks to isolate portions of our code, and be sure that "what happens in the block stays in the block" (kinda like Las Vegas).
Organizing our code in blocks allow us also to structure the execution of the program, with control flow constructs like if

if, else

Sometimes we want to run code only if something is true. That’s what the if statement is for.
const myAge = 20 console.log("Am I an adult?") if (myAge >= 18) { console.log("Yes I am!") }
This prints:
Am I an adult? Yes I am!
As you can, see the code compares myAge and 18. In this case the >= operator returns true, so the block gets executed. If the condition is not true, the block doesn't get executed.
const myAge = 17 console.log("Am I an adult?") if (myAge >= 18) { console.log("Yes I am!") }
This prints:
Am I an adult?
You can add an else block to handle the opposite case:
const myAge = 17 console.log("Am I an adult?") if (myAge >= 18) { console.log("Yes I am!") } else { console.log("No, I am not.") }
This prints:
Am I an adult? No, I am not.
Both the if and else blocks are still blocks - so variables declared inside them don’t exist outside.
If we want to be sure that something is not true, what can we do?
Well, as previously discussed, JavaScript has a "not" operator, which flips booleans. So we can do
const myAge = 17 const adult = myAge >= 18 console.log("Am I an adult?") if (!adult) { console.log("No, I am not.") }
This still prints:
Am I an adult? No, I am not.
Because we used the ! operator to invert the adult variable.
if (!adult) {...} should be read as "if not adult..."
Using blocks, logic and comparison operators, we can structure the execution of the program, by defining variables that must be true (or false) for something to happen.

while, break, continue

A while loop repeats code as long as a condition is true.
let count = 0 while (count < 3) { console.log("Count is", count) count = count + 1 } console.log("the loop is over!")
This prints:
Count is 0 Count is 1 Count is 2 the loop is over!
When count becomes 3, the loop stops.
You can stop a loop early using break:
let number = 1 // Start with number 1 while (true) { // This condition is always true, so this loop will run forever unless we stop it console.log(number) // Print the current number if (number === 3) { // If the number is 3, stop the loop break } number = number + 1 // Add 1 to the number }
This prints:
0 1 2
Because when the number becomes 3, the if block gets executed and it stops the loop.
You can skip the rest of a loop using continue:
let number = 0 // Start with number 0 while (number < 5) { // Keep going while number is less than 5 number = number + 1 // Add 1 to the number if (number === 3) { // If the number is 3 continue // Skip the rest of the block and go to the next iteration of the loop } console.log(number) // Print the number }
This prints:
1 2 4 5
Because when the number was 3, continue made the program skip the line that prints the number.

for ... of ...

If you have an array, and want to do something to every item in it, you can use for ... of ... {...}.
const fruits = ["apple", "banana", "cherry"] for (const fruit of fruits) { console.log(fruit) }
This prints:
apple banana cherry
The block will get executed once for each element of the array.
fruit here is a new variable that takes the value of each item in the array, to operate on it inside the block.

for ... in ...

You can use for ... in to loop over the keys (indexes) of an array:
const fruits = ["apple", "banana", "cherry"] for (const index in fruits) { console.log(index) }
This prints:
0 1 2
You can use the index to get the value too:
const fruits = ["apple", "banana", "cherry"] for (const index in fruits) { console.log(fruits[index]) }
This prints the same as for ... of:
apple banana cherry
In practice, for arrays, you should prefer using for ... of, as it's simpler and cleaner.

Bounded loops

Sometimes we want to loop a specific number of times, or in general write a piece of code that repeats a block while keeping track of something. That’s what a bounded for loop is good for. A bounded loop usually takes three conditions, separated by a semicolon ;, as in (... ; ... ; ....).
for (let i = 0; i < 3; i = i + 1) { console.log(i) }
This prints:
0 1 2
Let’s explain it:
  • let i = 0: declares a variable to be used in the block (in this case it's a counter that starts at 0)
  • i < 3: declares a condition to be true for the block to be executed ( in this case is "repeat while i is less than 3")
  • i = i + 1: declare some code to be run after each execution of the block (in this case "increase i by 1")
As you can see the bounded loop us to declare more complex conditions for the repeated execution of a piece of code, but most of the times it's not necessary.

Block labels

If you have to write more complex control flow, JavaScript lets you name a block using a label that can be used by break or continue for specifying where to jump back.
Example:
outer: { console.log("We're inside the outer scope.") inner: { console.log("We're inside the inner scope.") break outer } console.log("This will not run") } console.log("Done")
This prints:
We're inside the outer scope We're inside the inner scope. Done
We used break outer to exit the outer block entirely.
You can also label loops. Let's take this example:
// Declare a variable to count the total number of days in a year let totalDaysInOneYear = 0 // Declare one variable per month, with the number of the month const january = 1 const february = 2 const march = 3 const april = 4 const may = 5 const june = 6 const july = 7 const august = 8 const september = 9 const october = 10 const november = 11 const december = 12 // Declare an array that holds the months that have 30 days const monthsWith30Days = [ april, june, september, november ] // Declare variables to keep track of the month and day we're in let currentMonth = january let currentDay = 1 monthsLoop: while (true) { // Start a loop labeled "monthsLoop" to process each month daysLoop: while (true) { // Start a loop labeled "daysLoop" to process each day in the month totalDaysInOneYear = totalDaysInOneYear + 1 // Increase the total number of days we counted by 1 if ( // We want to check if we're at the end of the month. currentDay === 31 // Check if the current day is 31 (for months with 31 days)... || currentDay === 30 && (monthsWith30Days.includes(currentMonth)) // ...or 30 if it's among the 30-days months... || currentDay === 28 && (currentMonth === february) // ...or 28 if it's February. If it's any of these three, then: ){ currentMonth = currentMonth + 1 // Move to the next month currentDay = 1 // Reset the day to 1 for the new month break daysLoop // Exit the inner loop (which tracks days) and go back to the outer loop (which tracks months) } else { currentDay = currentDay + 1 } // Otherwise, we're not at the end of the month, and we just move to the next day } if (currentMonth > 12) { // After processing a month, check if we've gone past December break monthsLoop // If so, break the outer loop and stop the day-counting process } } console.log(totalDaysInOneYear) // Print the total number of days in the year (should be 365)
This was a very boring example but hopefully it clarified the (occasional) need for labels.