Hoisting
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 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
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
/const
hoisting — Grammar and types guide -
function
hoisting — Functions guide -
class
hoisting — Classes guide -
import
hoisting — JavaScript modules
See also
-
var
statement — datarist -
let
statement — datarist -
const
statement — datarist -
function
statement — datarist