Hoisting
JavaScript Hoisting refers to the process whereby the interpreter appears to move the declaration of functions, variables, classes, or imports to the top of their {{glossary("scope")}} , prior to execution of the code.
Hoisting is not a term normatively defined in the ECMAScript specification. The spec does define a group of declarations as HoistableDeclaration, but this only includes function, function*, async function, and async function* declarations. Hoisting is often considered a feature of var declarations as well, although in a different way. In colloquial terms, any of the following behaviors may be regarded as hoisting:
- Being able to use a variable’s value in its scope before the line it is declared. (“Value hoisting”)
- Being able to reference a variable in its scope before the line it is declared, without throwing a
{{jsxref("ReferenceError")}}, but the value is alwaysundefined. (“Declaration hoisting”) - The declaration of the variable causes behavior changes in its scope before the line in which it is declared.
- The side effects of a declaration are produced before evaluating the rest of the code that contains it.
The four function declarations above are hoisted with type 1 behavior; var declaration is hoisted with type 2 behavior; let, const, and class declarations (also collectively called lexical declarations) are hoisted with type 3 behavior; import declarations are hoisted with type 1 and type 4 behavior.
Some prefer to see let, const, and class as non-hoisting, because the temporal dead zone strictly forbids any use of the variable before its declaration. This dissent is fine, since hoisting is not a universally-agreed term. However, the temporal dead zone can cause other observable changes in its scope, which suggests there’s some form of hoisting:
const x = 1;
{
console.log(x); // ReferenceError
const x = 2;
}
If the const x = 2 declaration is not hoisted at all (as in, it only comes into effect when it’s executed), then the console.log(x) statement should be able to read the x value from the upper scope. However, because the const declaration still “taints” the entire scope it’s defined in, the console.log(x) statement reads the x from the const x = 2 declaration instead, which is not yet initialized, and throws a {{jsxref("ReferenceError")}} . Still, it may be more useful to characterize lexical declarations as non-hoisting, because from a utilitarian perspective, the hoisting of these declarations doesn’t bring any meaningful features.
Note that the following is not a form of hoisting:
{
var x = 1;
}
console.log(x); // 1
There’s no “access before declaration” here; it’s simply because var declarations are not scoped to blocks.
For more information on hoisting, see:
var/let/consthoisting — Grammar and types guidefunctionhoisting — Functions guideclasshoisting — Classes guideimporthoisting — JavaScript modules