What is Hoisting in JavaScript?
When your JavaScript is being compiled, variables and function definitions are made available to the JavaScript engine. When the engine executes your code, the declared var
s and function
s from the compilation phase are made available before their value assignments, irrespective of the order in which they were written.
This can be envisaged as “hoisting” the declarations to the top of the current scope. The variable value assignments on the other hand are in place where they were authored, below the declarations.
This is why you can call functions that are declared underneath the invoking code.
someFunction();
function someFunction() {
console.log(“Hello”); // Hello
}
The JavaScript engine sees this as:
function someFunction() {
console.log(“Hello”); // Hello
}
someFunction();
The function declaration is available to the JS engine at the top of the scope. This is the same with var
s, but only the declaration, not the assignment of a value to the var
.
console.log(x); // undefined
var x = 1;
Note the value of x
is the value undefined
, and not a ReferenceError
. This is because the JavaScript engine sees it as:
var x; // declaration hoisted only, not the assignment
console.log(x); // undefined
x = 1;
This can have unexpected results if you declare variables and functions with the same name, or declare them further down in the code (mistakenly or otherwise) after assigning them values.
While true for var
s and functions, let
and const
declarations are not hoisted.
console.log(x); // ReferenceError: Cannot access 'x' before initialization
let x = 1;
Note the ReferenceError
in this example; the let
declaration is not “hoisted” or declared above the console.log(x)
, as it was with var
.
Note that the var
s and function
s are hoisted relative to the current scope, so the usual lexical scope rules apply for functions and variables declared in functions, they are not hoisted to the top of the global scope.
var a = 1;
someFunction();
function someFunction() {
anotherFunction();
function anotherFunction() {
console.log(a); // 1
}
}
anotherFunction(); // ReferenceError: anotherFunction is not defined
// anotherFunction remains within the scope of someFunction
Seen by the JS engine as:
var a;
a = 1;
function someFunction() {
function anotherFunction() {
console.log(a); // 1
}
anotherFunction();
}
someFunction();
anotherFunction(); // ReferenceError: anotherFunction is not defined
// anotherFunction remains within the scope of someFunction
It’s therefore common practice to declare var
s before assigning them values (or at the same time as assigning values), placing them at the top of the current scope to avoid confusion. Bear in mind that let
s and const
s will not be available for reference before declaration (and will result in a ReferenceError
), as they are with var
s.
If you have any questions or comments or want to connect, you can follow me on Twitter, or sign up to the newsletter in the footer for front-end articles to your inbox 👇