Hoisting is JavaScript's default behavior of moving declarations to the top of their scope.
To begin with, learning this mechanism, let's make sure we understand the differences between declaration, initialization, and assignment.
To declare variable means to register it in the corresponding scope:
var a; // Declared
let a; // Declared
const a; // SyntaxError: Missing initializer in const declaration
Important note: const
must be initialized with value at the time of definition.
To initialize variable means to allocate some space in the memory for it.
Just after a variable is declared, it is automatically initialized:
var a; // Declared and automatically initialized
let a; // Declared and automatically initialized
const a; // SyntaxError: Missing initializer in const declaration
To fix an error SyntaxError: Missing initializer in const declaration
we have to initialize const
variable at the time of declaration:
const a = 10; // The proper way
This is a step of assigning value to previously declared and initialized variable:
var a; // Declaration and initialization
a = 10; // Assignment;
// All in one
var a = 10;
Consider the following code:
console.log(a); // Prints "undefined"
var a = 10;
Do you know why we receive "undefined" instead of ReferenceError: a is not defined
?
Javascript hoisted variable declaration. This is how the above code is seen by an interpreter:
var a;
console.log(a); // Prints "undefined"
a = 10;
Thanks to the hoisting mechanism, we are allowed to use variables before they are declared. However, we have to be careful, because hoisted variables are initialized with undefined
.
Make sure to always declare and initialize a variable before using it.
Variables are also hoisted in the function scope:
function example() {
console.log(a); // Prints "undefined"
var a = 10;
};
example();
Interpretation:
function example() {
var a;
console.log(a); // Prints "undefined"
a = 10;
};
example();
Important note: In order to avoid unexpected behavior, do not access variables before you declare it.
As we remember from the previous article, let
and const
are hoisted, but not initialized:
console.log(a); // ReferenceError: a is not defined
let a = 10;
console.log(b); // ReferenceError: b is not defined
const b = 10;
Before we move to this section, let's remember how functions can be defined in JavaScript:
function
keyword followed by the name. Function declaration is hoisted:printNumber(); // Prints "10"
function printNumber() {
console.log(10);
};
printNumber(); // Uncaught ReferenceError: Cannot access 'printNumber' before initialization
const printNumber = function() {
console.log(10);
};
printNumber(); // Uncaught ReferenceError: Cannot access 'printNumber' before initialization
const printNumber = () => {
console.log(10);
};
Variable assignments take precedence over function declaration:
function a(){
console.log("Function a")
};
var a = "Variable a";
console.log(a); // Prints "Variable a"
Function declarations take precedence over variable declaration:
function a(){
console.log("Function a")
};
var a;
console.log(a); // Prints "Function a"
function a(){
console.log("Function a")
};
let a; // Duplicate declaration "a"
function b(){
console.log("Function b")
};
const b; // SyntaxError: Identifier "b" has already been declared
It's pretty much the expected behavior, as you should always remember to choose unique names for your variables and functions.
Imaging JavaScript interpreter making 2 iterations over your code. Firstly, it moves all variable and function declarations to the top of their scope and lastly, it executes your code from top to bottom (making assignments, executing functions, etc.).
Hoisting is often misunderstood concept even by experienced developers, so always be aware of it when writing JavaScript code.