Hoisting
JavaScript Hoisting refers to the process whereby the interpreter appears to move the declaration of functions, variables or classes to the top of their 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
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 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.
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:
js
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 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:
js
{
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
/const
hoisting — Grammar and types guidefunction
hoisting — Functions guideclass
hoisting — Classes guide
See also
var
statement — MDNlet
statement — MDNconst
statement — MDNfunction
statement — MDN