9 Questions on Hoisting in JavaScript Answered
Table of contents Why does JavaScript have hoisting? Why did JavaScript have hoisting in its early days? Why does JavaScript have hoisting to date? How does hoisting work in JavaScript? Explain hoisting with an example var hoisting let and const hoisting Function hoisting class hoisting import hoisting Why do we need hoisting in JavaScript? Why is hoisting still supported in JavaScript if it generally confuses code? What is the difference between function hoisting and variable hoisting? Can we avoid hoisting in JavaScript? What are the advantages of hoisting? Do let and const get hoisted? Hoisting is perhaps one of the most peculiar aspects of JavaScript. It's something which doesn't get help from experience of another programming language — as far as I know, almost no other programming language exhibits hoisting like JavaScript does. In fact, to some extent, even the term 'hoisting' is perhaps nascent for a programming language. Due to its nature, hoisting is either misunderstood completely or understood without crystal-clear clarity. In this respect, there are numerous questions people tend to ask with regards to hoisting and that why is it even something to worry about in 2025. This article hopefully aims to clear all your confusions regarding hoisting in JavaScript. By the end of it — and I encourage you to read till the end — you'll be absolutely confident in your ability to reason about the whole intuition behind hoisting and when you might leverage it, if at all. Why does JavaScript have hoisting? This question can be broken down into two questions: Why did JavaScript have hoisting in its early days? Why does JavaScript have hoisting to date? Let's answer each one. Why did JavaScript have hoisting in its early days? Remember that JavaScript had extreme simplicity as a design goal. The goal was was to appeal to non-technical people so they could easily add simple interactions in their websites. And to a large extent, this goal was indeed met. Speaking of this simplicity, many features were added to the language exactly for this very reason — simplicity. Hoisting is an example. The initial motivation in JavaScript was function hoisting, whereby a function is accessible even before its definition. Variable hoisting, as per Brendan Eich's own words, was an unintended consequence of function hoisting. So the reason why JavaScript had hoisting was to make the language simpler. Without a doubt, it would've been superbly convenient for people to call functions without having to worry about whether they were even declared before that or not. Why does JavaScript have hoisting to date? This is answered later below. How does hoisting work in JavaScript? We all have heard of the fact that hoisting works by taking the declaration at the top of its scope. In reality, this is true but with some abstraction applied to the explanation. Let's dive a little bit deeper into how hoisting actually works... First the code is parsed and then the parsed version goes through a first pass. In this first pass, all variable and function declarations are found and taken to the very top of start of scopes. In other words, in this first pass, the interpreter basically hoists all declarations. In the second pass, the code finally gets executed. Is this more work for the interpreter? Definitely yes. Does it affect performance negatively? Not much, if at all. The thing is that hoisting is done once — in the first pass after parsing — so there's no continual overhead as a script runs add. Furthermore, the overhead of hoisting in the initial run is also almost negligible. Explain hoisting with an example Actually there are many classifications of hoisting. So this question boils down to showing an example for every classification. var hoisting Let's review var hoisting to begin with: // This doesn't throw because of `var` hoisting console.log(x); var x = 10; Output: undefined let and const hoisting Now, let's see let (const works similarly): // This throws due to the TDZ console.log(x); let x = 10; Output: Uncaught ReferenceError: Cannot access 'x' before initialization Before the line where x is declared, we try to access it. This immediately throws an error because the region before the line where a let declaration appears, in its respective scope (global in this case), is a temporal dead zone where the variable's access fails. Keep in mind that because knowledge of the fact is kept that a let declaration appears later when we access x in console.log(x), there is surely some kind of pre-processing involved here before executing the code. I personally would refrain from calling this as hoisting of let, leaving the term 'hoisting' to only refer to a case where it's allowed to refer to an identifier before its declaration. Function hoisting
Table of contents
-
Why does JavaScript have hoisting?
- Why did JavaScript have hoisting in its early days?
- Why does JavaScript have hoisting to date?
- How does hoisting work in JavaScript?
-
Explain hoisting with an example
-
var
hoisting -
let
andconst
hoisting - Function hoisting
-
class
hoisting -
import
hoisting
-
- Why do we need hoisting in JavaScript?
- Why is hoisting still supported in JavaScript if it generally confuses code?
- What is the difference between function hoisting and variable hoisting?
- Can we avoid hoisting in JavaScript?
- What are the advantages of hoisting?
- Do
let
andconst
get hoisted?
Hoisting is perhaps one of the most peculiar aspects of JavaScript. It's something which doesn't get help from experience of another programming language — as far as I know, almost no other programming language exhibits hoisting like JavaScript does. In fact, to some extent, even the term 'hoisting' is perhaps nascent for a programming language.
Due to its nature, hoisting is either misunderstood completely or understood without crystal-clear clarity. In this respect, there are numerous questions people tend to ask with regards to hoisting and that why is it even something to worry about in 2025.
This article hopefully aims to clear all your confusions regarding hoisting in JavaScript. By the end of it — and I encourage you to read till the end — you'll be absolutely confident in your ability to reason about the whole intuition behind hoisting and when you might leverage it, if at all.
Why does JavaScript have hoisting?
This question can be broken down into two questions:
- Why did JavaScript have hoisting in its early days?
- Why does JavaScript have hoisting to date?
Let's answer each one.
Why did JavaScript have hoisting in its early days?
Remember that JavaScript had extreme simplicity as a design goal. The goal was was to appeal to non-technical people so they could easily add simple interactions in their websites. And to a large extent, this goal was indeed met.
Speaking of this simplicity, many features were added to the language exactly for this very reason — simplicity. Hoisting is an example.
The initial motivation in JavaScript was function hoisting, whereby a function is accessible even before its definition. Variable hoisting, as per Brendan Eich's own words, was an unintended consequence of function hoisting.
So the reason why JavaScript had hoisting was to make the language simpler.
Without a doubt, it would've been superbly convenient for people to call functions without having to worry about whether they were even declared before that or not.
Why does JavaScript have hoisting to date?
This is answered later below.
How does hoisting work in JavaScript?
We all have heard of the fact that hoisting works by taking the declaration at the top of its scope. In reality, this is true but with some abstraction applied to the explanation.
Let's dive a little bit deeper into how hoisting actually works...
First the code is parsed and then the parsed version goes through a first pass. In this first pass, all variable and function declarations are found and taken to the very top of start of scopes. In other words, in this first pass, the interpreter basically hoists all declarations. In the second pass, the code finally gets executed.
Is this more work for the interpreter? Definitely yes.
Does it affect performance negatively? Not much, if at all. The thing is that hoisting is done once — in the first pass after parsing — so there's no continual overhead as a script runs add. Furthermore, the overhead of hoisting in the initial run is also almost negligible.
Explain hoisting with an example
Actually there are many classifications of hoisting. So this question boils down to showing an example for every classification.
var
hoisting
Let's review var
hoisting to begin with:
// This doesn't throw because of `var` hoisting
console.log(x);
var x = 10;
Output:
undefined
let
and const
hoisting
Now, let's see let
(const
works similarly):
// This throws due to the TDZ
console.log(x);
let x = 10;
Output:
Uncaught ReferenceError: Cannot access 'x' before initialization
Before the line where x
is declared, we try to access it. This immediately throws an error because the region before the line where a let
declaration appears, in its respective scope (global in this case), is a temporal dead zone where the variable's access fails.
Keep in mind that because knowledge of the fact is kept that a let
declaration appears later when we access x
in console.log(x)
, there is surely some kind of pre-processing involved here before executing the code.
I personally would refrain from calling this as hoisting of let
, leaving the term 'hoisting' to only refer to a case where it's allowed to refer to an identifier before its declaration.
Function hoisting
Anyways, let's now see function hoisting:
// The function is accessible even before its definition
greet();
function greet() {
console.log('Hello world!');
}
Output:
Hello world!
By far, the only useful aspect of hoisting lies in this type — function hoisting.
class
hoisting
Next up, we have class
hoisting, which is more or less just like let/const
hoisting:
console.log(Foo);
class Foo {}
Output:
Uncaught ReferenceError: Cannot access 'Foo' before initialization
In the code above, we try accessing the Foo
class before its declaration. The code throws an error because of the temporal dead zone in which Foo
is prior to its declaration.
Again, I'd refrain from really calling this as 'hoisting' of class
— it's invalid to refer to the class prior to its declaration, likewise if our definition of 'hoisting' only allows for cases where it's valid to access an identifier before its declaration, then this doesn't apply.
import
hoisting
And then finally there's import
hoisting as well but that's quite apparent because JavaScript clearly states that all import
statements are processed at the start of evaluating a given script:
constants.js
export const a = 10;
// This works because of `import` hoisting
console.log(a);
import { a } from './constants.js';
Output:
10
In the code above, the console.log(a)
statement logs the value of a
, which is 10
, without any issues even though the import
declaration occurs after it. This is by virtue of import
hoisting.
Further reading:
To learn more about the import
statement in JavaScript, refer to JavaScript Modules — Basics.
Why do we need hoisting in JavaScript?
This question can also be rephrased as: What is the application of hoisting in JavaScript?
Well, there isn't anything for which we explicitly require hoisting in JavaScript. That is, hoisting isn't something which we need for our JavaScript applications; it's just a casual behavior exhibited as per the language's design.
To better understand what this means, let's make a quick comparison.
Consider the default-valued parameter feature in JavaScript (introduced with ES6).
Why do we need a default-valued parameter? Well, when we need to define a function with a parameter that isn't required per se, and in case of not being provided with a corresponding argument, the parameter must assume a default value, that's when we need a default-valued parameter.
You see, there is a clear-cut application of the default-valued parameter feature in JavaScript. However, there is nothing like this for hoisting. Hoisting is, more or less, not a utilitarian feature but rather a behavioral feature; it only makes up the behavior of JavaScript when executed.
And that's why there isn't any real application of hoisting when we're working with JavaScript.
Why is hoisting still supported in JavaScript if it generally confuses code?
Today, in JavaScript, the biggest reason why hoisting is still supported is for backwards compatibility. Legacy scripts might rely heavily upon hoisting and so removing it completely would mean bringing these scripts to a halt in new browsers.
Besides that, hoisting is also supported for convenience sake. It won't be completely wrong to say that function hoisting is particularly useful at times (though, it isn't something that I think other developers should eagerly aim for or that new languages should copy in any way).
What is the difference between function hoisting and variable hoisting?
Function hoisting refers to the behavior whereby a function is made available at the start of its respective scope before its declaration site.
In contrast, variable hoisting refers to the behavior whereby a variable's declaration is made available at the start of its respective scope, for var
, or where the variable is entered into a temporal dead zone at the start of its respective scope, for let
(and const
too), prior to its declaration.