Unlike languages like C, variables and functions in JavaScript are not declared at the point of use. Instead, no matter where functions and variables are declared, they are moved to the top of their scope hoisted
and assigned a default value of undefined until they're reached in code, while assignments are left in place.
What really happens, is that during compile time, the declarations are put into memory first, but physically remain in place in code. What this means is that you get access to functions and variables before they’re declared in code.
This only applies to declarations, not to expressions, and not to initializing an undeclared variable.
Example:
a = "Set the value";
console.log(a);
var a;
Set the value
will produce the same output as declairing it before.
var a;
a = "Set the value";
console.log(a);
Set the value
Variable Hoisting
When a variable declaration is encountered by the interpreter, it creates storage for that variable. This storage contains the value undefined until it is assigned in the code.
For example, the following code defines the variable after the value has already been set and accessed. However it will still function corectaly and output: Set the value
a = "Set the value";
console.log(a);
var a;
Set the value
The keyword used when defining a variable will determine whether or not the variable is hoisted.
Variables defined with the keyword var
are hoisted, and variables defined with the keyword let
and const
are not.
Hoisted variables
a = "Hoisted";
var a;
console.log(a);
Hoisted
Not Hoisted variables
a = "Not Hoisted";
let a;
console.log(a);
ReferenceError: Cannot access 'a' before initialization
a = "Definition Hoisted";
let a;
console.log(a);
SyntaxError: Missing initializer in const declaration.
Variable Hoisting Scope
When the variable is used inside a scope, the variable is hoisted only to the top of the scope. For example, the variable a
defined inside this function will only be hoisted to the top of the function, resulting in a ReferenceError: a is not defined
when accessed at the bottom of this script.
function functionScope() {
a = 'Scope Hoisting';
console.log(a);
var a;
}
functionScope();
console.log(a);
Scope Hoisting
ReferenceError: a is not defined
In the above example, variable a
is hoisted to the top of its scope and is only accessible inside the functionScope
function.
Function Hoisting
Function hoisting works similarly to variable hoisting; this is why you can call a function in code before you declare it.
console.log(testFunction());
function testFunction(){
return "Function output";
}
Function output
An error occurs if a function is used as an expression as only declarations are hoisted.
console.log(functionExpression());
let functionExpression = function(){
return "Function output";
}
ReferenceError: functionExpression is not defined
Best Practices
Hoisting can cause undesirable and difficult-to-debug outcomes.
It is best to avoid hoisting issues and declare variables and functions first before using them. When defining variables, unless you have a specific need, it's generally better to use let than var.