How to conditionally run JS code

Let's try writing our first conditional using an if statement. So that if we a condition is met, if something is true, we do something.

For example, let's say we have an ecommerce app where products are on sale or not. So let's take a product with a given price, say 20 and create a var variable for it. We'll also track whether we're having a sale with a variable, called isSale, which will either be true or false:

var price = 20;
var isSale = false;

If we're having a sale, if isSale is true, we'll decrease the price by 2 dollars and put it in a new price variable that will just live in that if block:

var price = 20;
var isSale = false;

if (isSale) {
  var price = 20 - 2;
}

So let's check how things work with console.log. We'll log the sale price as well as the regular price:

var price = 20;
var isSale = false;

if (isSale) {
  var price = 20 - 2;
  console.log("sale price", price);
}
console.log("price", price);

When we're not having a sale, is isSale is false, the if condition doesn't run and we get the default price 20. But when there is a sale, what do you think we're going to get?

var price = 20;
var isSale = false;

if (isSale) {
  var price = 20 - 2;
  console.log("sale price", price); // sale price 18
}
console.log("price", price); // price 18

We see that both the sale price and the regular price are 18. So the new price variable is not just living in the if block, it lives in the outside context too, which as you might recall, is called scope. In other words, variables declared with var live in the global scope, or when we cover functions, it lives in the scope of the function.

Variable shadowing

var totally ignores the code block, the curly braces of the if statement, and as a result, the original price variable is changed instead of creating a new one. Problems would emerge if we want to use the original price value of 20 later in our program.

The phenomenon of one variable overriding any variables of the same name that belong to a wider scope is called variable shadowing. The price variable created in the if block shadows or overrides the other price variable. Variable shadowing exists specifically as a result of function scoping.

Fortunately we can fix this problem by replacing var variables with let. And that's because an additional feature of let is that it is block-scoped, which means that any variable created in a block doesn't exist and cannot be accessed outside of it.

So let's change all of the variable declarations from var to let and see what happens. What do you think will happen?

let price = 20;
let isSale = true;

if (isSale) {
  let price = 20 - 2;
  console.log("sale price", price); // sale price 18
}
console.log("price", price); // price 20

Since the inner price variable is block scoped, the two don't conflict and the two are totally separate. In the block, price is the sale price. Outside, it's the original price.

Additionally, variables made with const are also block scoped, so if we use const instead of let:

const price = 20;
const isSale = true;

if (isSale) {
  const price = 20 - 2;
  console.log("sale price", price); // sale price 18
}
console.log("price", price); // price 20

Again, there are no conflicts.

Block scoping prevents variable shadowing

So just like the benefit of using const to indicate that it can't be reassigned, the block scoping feature of let and const variables help us know our program better and indicate our intent to other developers (plus ourselves). Variables declared with let and const within blocks will only exist in that block. We don't have to worry about it conflicting with any variables outside of it.