Hoisting
JavaScriptHoisting refers to the process whereby the interpreter appears to move thedeclaration of functions, variables, classes, or imports to the top of theirscope, 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 asHoistableDeclaration, but this only includesfunction,function*,async function, andasync function* declarations. Hoisting is often considered a feature ofvar 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 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, andclass declarations (also collectively calledlexical declarations) are hoisted with type 3 behavior;import declarations are hoisted with type 1 and type 4 behavior.
Some prefer to seelet,const, andclass as non-hoisting, because thetemporal 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 theconst x = 2 declaration is not hoisted at all (as in, it only comes into effect when it's executed), then theconsole.log(x) statement should be able to read thex value from the upper scope. However, because theconst declaration still "taints" the entire scope it's defined in, theconsole.log(x) statement reads thex from theconst x = 2 declaration instead, which is not yet initialized, and throws aReferenceError. 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); // 1There's no "access before declaration" here; it's simply becausevar 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