Explain What Hoisting Is in JavaScript
February 13, 2023
The article titled What Is the Difference Between var, let and const in JavaScript? discusses the differences between var
, let
, and const
in JavaScript and how they behave with regards to hoisting. This article provides a more detailed explanation of what hoisting is and the differences in hoisting behavior.
What Is Hoisting?
Most people may have used a function before declaring it when writing JavaScript code, such as the following code:
sayHello(); // Hello
function sayHello() {
console.log("Hello");
}
However, executing such code will not report an error, and the reason is because of hoisting.
Hoisting is not a formal definition in the ECMAScript® 2015 Language Specification, but it is used to describe the concept of storing variable and function declarations in memory during the JavaScript compilation phase.
This feature causes function and variable declarations to be hoisted to the top of the scope, even if they are actually defined below. Note, however, that the JavaScript engine doesn't actually move the code to the top, it's just a description of the concept.
Variable and Function Hoisting
var
Hoisting
var
hoisting means that during the compilation phase, the JavaScript engine will hoist allvar
variable declarations to the top of the function scope. Although the variable declaration is hoisted, it will not be assigned a value. In the following code, the result of calling name early will be undefined
instead of Tom
.
console.log(name); // undefined
var name = "Tom";
let
Hoisting
Many people mistakenly believe that let
does not hoist, because if we use it before declaring let
, we will get the following error.
console.log(greeting); // Uncaught ReferenceError: greeting is not defined
let greeting = "hi there";
The above code throws an error not because let
has no hoisting. Although hoisting is not defined in the standard specification, conceptually, let
and const
also have hoisting behavior, but there are the following differences:
var
will be hoisted tofunction scope
, butlet
andconst
will only be hoisted toblock scope
.- When
var
creates a variable and defines the variable scope, it will automatically initialize the variable value toundefined
at the same time. However, whenlet
hoists the variable to block scope, it will not initialize the variable. This state can be called uninitialized, and there is another common saying that variables defined bylet
andconst
currently exist in the Temporal Dead Zone (TDZ).
Function Hoisting
Function declarations are also hoisted. The difference from var hoisting is that function hoisting also creates function objects, so they can be called before declarations.
foo(); // 1
function foo() {
console.log(1);
}
However, it should be noted that if it is a function expression, the promotion behavior will be the same as the declared variable. In the following code snippet, the foo
function declared with var, when used before the declaration, the current value will be undefined
, so calling undefined
will throw an error.
foo(); // Uncaught TypeError: foo is not a function
var foo = function () {};
When the foo function declared with let
is used before the declaration, foo is in the temporary dead zone at this time, so calling foo
will report an error.
foo(); // Uncaught ReferenceError: foo is not defined
let foo = function () {};
Why Is There a Temporal Dead Zone (TDZ) Error?
Many articles mention that the benefit of the Temporal Dead Zone (TDZ) error is to prevent us from using a variable before it is declared. However, there is another key design concept.
As the author of You Don't Know JS explains in this course, the TDZ error is actually designed for const
. Imagine if const
had the same hoisting behavior as var
. In that case, accessing a const
variable before its declaration would return an undefined value. However, we know that const
is a constant, and its value should not change in the same scope. If we first get undefined and then a different value, it would violate the specification. Therefore, the TDZ error was designed to prevent this situation from happening.