Hoisting
Ever called a function above where you wrote it and wondered why it still worked? Or logged a var before assigning it and gotten undefined instead of an error? That's hoisting — JavaScript's two-phase way of preparing each scope before running it.
Learn Hoisting in our free JavaScript course — a beginner-friendly interactive lesson with runnable examples, a practice exercise and a quick recall.
Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Understanding it demystifies a whole category of "how is this even running?" moments and makes you far better at reading other people's code.
📚 Prerequisites: Know your variables and functions . The next lesson on Scope pairs perfectly with this one.
💡 Running Code Locally: While this online editor runs real JavaScript, some advanced examples may have limitations. For the best experience:
🎬 Real-World Analogy: Think of a stage crew before a play:
JavaScript runs each scope in two passes. First the creation phase scans the code and registers every declared name. Then the execution phase runs your code top to bottom, doing the actual assignments. "Hoisting" is just the name for that first pass making names available before the lines that assign them.
A var declaration is hoisted, but only the name — the value isn't assigned until its line runs. So reading it earlier gives undefined rather than an error. This silent undefined is exactly the kind of bug let / const were designed to prevent.
Only function declarations are fully hoisted. A function stored in a variable (a function expression or arrow) follows the variable's rules. With var the name is hoisted as undefined , so calling it early throws "is not a function".
Fill in the expected value the first log prints, given how var hoists.
let and const are hoisted too — but into the Temporal Dead Zone . The name exists from the top of the block, yet touching it before its declaration throws a ReferenceError . That's a feature: it converts use-before-declare mistakes from silent undefined bugs into immediate, obvious errors.
The behaviour you see depends entirely on how the name was declared. Here's the whole story in one runnable snippet, with guards so nothing crashes the demo.
Reorder the snippet (move the declaration up) so it logs 9 without relying on hoisting.
These lines are scrambled. Reorder them so the code runs cleanly with no TDZ error and logs 10 .
Why: the function declaration may sit anywhere (it's fully hoisted), but price is a const — it must be declared before any line that reads it.
Predict the output before revealing the answer.
undefined — var x is hoisted, but the value 7 isn't assigned until its line runs.
ReferenceError — y is in the Temporal Dead Zone until its declaration line.
hi — function declarations are fully hoisted, so calling before the line is fine.
Up next: Scope & var/let/const — where your names actually live. 🔭
Practice quiz
What are the two phases JavaScript runs each scope in?
- Parse and compile
- Creation and execution
- Read and write
- Hoist and assign
Answer: Creation and execution. First the creation phase registers declared names, then the execution phase runs the code and does assignments.
What does console.log(score) print if it runs before var score = 50?
- 50
- ReferenceError
- undefined
- null
Answer: undefined. var hoists the name but not the value, so reading it before assignment gives undefined.
Can you call a function declaration before the line where it is written?
- Yes, function declarations are fully hoisted
- No, it always throws
- Only if it uses var
- Only in strict mode
Answer: Yes, function declarations are fully hoisted. Function declarations are fully hoisted, so calling greet() before its declaration works.
What happens when you access a let variable before its declaration line?
- It returns undefined
- It returns null
- It throws a ReferenceError (Temporal Dead Zone)
- It returns 0
Answer: It throws a ReferenceError (Temporal Dead Zone). let and const are hoisted into the Temporal Dead Zone, so early access throws a ReferenceError.
Are function expressions assigned to a variable fully hoisted like declarations?
- Yes, identically
- No, they follow the variable's hoisting rules
- Yes, but only with const
- No, they are never hoisted at all
Answer: No, they follow the variable's hoisting rules. Only function declarations are fully hoisted; an expression follows its variable's hoisting (undefined for var, TDZ for let/const).
After hoisting, does the value assignment also move to the top of the scope?
- Yes, the whole line moves up
- No, only the declaration is hoisted; the assignment stays put
- Yes, but only for var
- No, nothing is hoisted
Answer: No, only the declaration is hoisted; the assignment stays put. Hoisting moves only the declaration; the assignment happens where it is written, which is why var reads undefined first.
What does typeof on a var name print before its assignment line runs?
- 'number'
- 'undefined'
- 'function'
- It throws
Answer: 'undefined'. A hoisted var is undefined until assigned, so typeof returns the string 'undefined'.
Why were let and const designed to use the Temporal Dead Zone?
- To run faster
- To turn use-before-declare bugs into loud errors instead of silent undefined
- To allow re-declaration
- To make them global
Answer: To turn use-before-declare bugs into loud errors instead of silent undefined. The TDZ converts sneaky use-before-declare mistakes into immediate, obvious ReferenceErrors.
What error occurs from let p = 1; let p = 2; in the same scope?
- TypeError
- ReferenceError
- SyntaxError: already declared
- No error
Answer: SyntaxError: already declared. Re-declaring the same name with let in one scope is a SyntaxError; reassign with p = 2 instead.
Is hoisting literally moving your source code to the top of the file?
- Yes, the engine rewrites the file
- No, it is a mental model for the two-phase creation-then-execution process
- Yes, but only function declarations move
- No, hoisting does not exist
Answer: No, it is a mental model for the two-phase creation-then-execution process. Source stays put; hoisting just describes how the creation phase registers names before execution, behaving AS IF they moved up.