如何证明let与const声明存在变量提升现象?
let and const in JavaScript Great question! This is one of JavaScript's trickiest nuances—those identical-looking ReferenceError messages sure do throw people off. Let's break down exactly how to prove that let and const do hoist, even though you can't access them before their declaration line.
First, Understand the Difference: Undeclared Variables vs. Temporal Dead Zone (TDZ)
When you access an undeclared variable like x, the JavaScript engine has no record of that variable existing at all—hence the Uncaught ReferenceError: x is not defined error.
For let/const variables, though, the engine does know the variable exists (thanks to hoisting) but locks it in the Temporal Dead Zone (TDZ) until the declaration line runs. The error message looks the same, but the underlying cause is totally different.
Test 1: Use typeof to Reveal the TDZ
The easiest way to spot the difference is with typeof:
- For an undeclared variable,
typeofreturns"undefined"(no error, because the engine doesn't recognize the variable as existing). - For a
let/constvariable in the TDZ,typeofthrows aReferenceError(the engine knows the variable exists, but won't let you touch it yet).
// Undeclared variable: no hoisting, no TDZ console.log(typeof x); // Outputs "undefined" — no error! // let variable in TDZ: hoisted, but locked console.log(typeof y); // Throws Uncaught ReferenceError: Cannot access 'y' before initialization let y;
If y wasn't hoisted, typeof y would behave just like typeof x and return "undefined". The error here proves the engine is aware of y's existence—it just won't let you access it yet.
Test 2: Block Scope Shadowing
Another way to see hoisting in action is with block-level shadowing. If let didn't hoist, accessing a variable inside a block before its declaration would fall back to the outer scope's variable. But instead, it targets the hoisted (but locked) block-scoped variable:
let outerVar = 100; { console.log(outerVar); // Throws ReferenceError: Cannot access 'outerVar' before initialization let outerVar = 200; // This declaration is hoisted to the top of the block }
If hoisting didn't happen here, console.log(outerVar) would output 100 (the outer scope's value). Instead, it throws an error because the engine has already created the block-scoped outerVar binding (thanks to hoisting) and is blocking access until the declaration runs.
Test 3: Function Scope TDZ
Same logic applies to function scopes. A let variable inside a function is hoisted to the top of the function, but stays in the TDZ until its declaration:
function myFunc() { console.log(funcVar); // Throws ReferenceError: Cannot access 'funcVar' before initialization let funcVar = "hello"; } myFunc();
If there was no hoisting, funcVar would be treated as a global variable (and throw a different error if it wasn't declared globally). The error here confirms the engine knows funcVar exists in the function scope—it's just locked in the TDZ.
Wrap-Up
To recap:
letandconstdo hoist—their bindings are created when the scope is entered (function or block).- The catch is they're immediately locked in the TDZ, so you can't access them until the declaration statement executes.
- The identical error messages are a red herring—use
typeoftests and scope shadowing to prove the hoisting is happening under the hood.
内容的提问来源于stack exchange,提问作者Shammi Hans

