

JavaScript Hoisting
Planted:
Status: decay
Hits: 74
If you are unfamiliar with the terminology below, check out:
An identifier is a sequence of characters in the code that identifies a variable
, function
, or property
.
For example: the myVar
string in var myVar = 1
.
Every time the compiler enters a scope, it starts registering declarations.
Each identifier will be moved to the top of a scope.
This is known as hoisting.
What scope the identifier moves to the top of depends on the type of declaration:
- ▪
function
, - ▪
var
or - ▪
let
,const
andclass
.
Imagine being a kid and having a messy room. You can put things wherever you like. But, when a parent comes in, they move everything. Socks moved to the socks draw. Dirty clothes thrown in the washing basket. Toys moved to the shelves...
Your room is like the scope, items are identifiers and your parents are the compiler. When you code something, you can put identifiers wherever you like in the scope. But, when the compiler enters the scope, it moves them to their proper place. This is hoisting.
function
A function
declared identifier will move to the top of the nearest block scope.
If none available, the nearest parent scope.
It will also be initialized to its associated function reference and can be used.
Below is an example of calling a function before it is declared.
It works because it is hoisted to the top of the global scope by the compiler before line: 1
is executed.
index.js
func()function func() {console.log('called')}
This only applies to formal functions (functions declared with the function
keyword), not function expressions:
- ▪
const func = () => { .. }
or - ▪
const func = function() { .. }
.
var
A var
declared identifier will move the top of the nearest function scope.
If none available, the global or module scope.
It will also be initialized to its default value of undefined
and can be used.
Even if you declare and initialize the variable on the same line, var myVar = 1
, only the identifier is hoisted.
The variable will be initialized to its correct value when the line of code is executed.
index.js
console.log(myVar)var myVar = 1;console.log(myVar)
Below is an example of a variable declared and initialized in a block scope.
Because it's declared as a var
, it is hoisted to the function scope.
This makes it accessible to the console.log
.
index.js
function myFunc(x) {if (x === 1) {var y = 1}console.log(y)}myFunc(1)
const, let and class
A const
, let
or class
declared identifier will move the top of the nearest block scope.
If none available, the nearest parent scope.
It will also be initialized to its default value of uninitialized
.
It will remain uninitialized until the compiler executes the line where is it declared.
Attempting to use it before then results in an error.
index.js
console.log(myVar)let myVar = 1;
TDZ
The above is an example of The Temporal Dead Zone.
A window of time where a variable is declared but uninitialized.
When a var
is hoisted, it is initialized with a default value of undefined
, so it has a TDZ of 0 in length and unobservable.
let
, const
and class
have an observable TDZ.
index.js
console.log(myVar)let myVar = 1
TDZ errors can be avoided by always putting let
, const
and class
declarations at the top of their scope.
This shrinks the TDZ to 0 length.
If the declaration isn't needed from the beginning, create an inner block scope:
Instead of this:
/index.js
function add1IfEven(x) {if (!x) {throw new Error("Input required")}const isEven = x%2 === 0return isEven ? x + 1 : x}
Do this:
/index.js
function add1IfEven(x) {if (!x) {throw new Error("Input required")}{const isEven = x%2 === 0return isEven ? x + 1 : x}}

Rules of Scope
Rules of scope, such as hoisting, are applied per scope instance.
During execution, each time a scope is entered, everything resets.
This is why using a const
within a loop doesn't throw aa already declared error after the 1st iteration.
index.js
for (let i = 0; i < 2; i++) {const myVar = iconsole.log(myVar)}
Feedback
Have any feedback about this note or just want to comment on the state of the economy?