ES2015 Lesson 2: Function scope, block scope, constants

In this lesson, we will introduce the let keyword for the purpose of declaring block scoped variables. You will also learn about defining block scoped constants, and the dangers of scoping, such as the temporal dead zone. We will conclude the lesson with best practices.

Var vs Let

Variables declared with var have function scope. They are accessible inside the function they are defined in.

Comment B may surprise you if you have not heard of hoisting. JavaScript hoists all declarations. Hoisting is a transformation that transforms the code

in the following form:

Variables declared with var are initialized to undefined. This is why the value of guessMe was undefined in comment B.

Variables declared with let have block scope. They are valid inside the block they are defined in.

Comment B may surprise you again. Even though let guessMe is hoisted similarly to var, its value is not initialized to undefined. Retrieving uninitialized values throws a JavaScript error.

The area described by comment B is the temporal dead zone of variable guessMe.

In logAge, we log undefined, as age is hoisted and initialized to undefined.

In logName, we reached the temporal dead zone of name by accessing it before the variable was defined.

You may find the temporal dead zone inconvenient at first sight. However, notice that the thrown error grasps your attention a lot better than a silent undefined value. Always be grateful for errors pointing out obvious mistakes during development, as the same mistakes tend to be a lot more expensive once they are deployed to production.

The temporal dead zone exists even if a variable with the same name exists outside the scope of the dead zone.

For a complete reference, the temporal dead zone exists for let, const, and class declarations. It does not exist for var, function, and function* declarations.


Declarations with const are block scoped, they have to be initialized, and their value cannot be changed after initialization.

Not initializing a constant also throws an error:

Const may also have a temporal dead zone.

Redeclaring another variable with the same name in the same scope will throw an error.

Use cases of let, const, and var

Rule 1: use let for variables, and const for constants whenever possible. Use var only when you have to maintain legacy code.

The following rule is also worth keeping.

Rule 2: Always declare and initialize all your variables at the beginning of your scope.

Using rule 2 implies that you never have to face with the temporal dead zone.

If you have a linter such as ESLint, set it up accordingly, so that it warns you when you violate the second rule.

If you stick to these two rules, you will get rid of most of the anomalies developers face.


Don’t forget to verify your solutions by clicking the Solutions link after the exercises.

Exercise 1: Check the following riddle:

Determine the values logged to the console.

Exercise 2: Modify the code such that all six console logs print out their values exactly once, and the printed values are the following:

You are not allowed to touch the console logs, just the rest of the code.

Exercise 3: Add the linter of your choice to your text editor or IDE. Configure your linter such that you never have to worry about leaving a temporal dead zone unnoticed.