JavaScript变量提升(hoisting):一次性扫描全代码还是按嵌套层级执行?
Hey there! Great question about hoisting—this is one of those nuanced JS concepts that’s easy to misinterpret, so I’m glad you’re digging into the mechanics behind it. Let’s break this down clearly:
First: Does the JS engine scan all nested functions down to the deepest scope upfront?
Nope, it doesn’t. JavaScript works on a scope-by-scope basis when processing declarations. Here’s how it goes:
- When your code starts running, the engine first processes the global scope: it looks for all function declarations and variable declarations (var, let/const, though let/const have "temporal dead zones") in this top-level scope and handles their hoisting.
- It only moves into nested scopes when those scopes are actually entered during execution. For example, if you have a function nested inside another function, the engine won’t scan or process that inner function’s scope until the outer function is called and its execution context is created. The deepest nested scopes are only processed when their parent functions run, not on the initial global scan.
Second: Are all function creation stages completed in a single initial scan?
Absolutely not. Hoisting is not a one-and-done, full-code operation. Each function’s creation (and the hoisting of its internal declarations) happens only when its containing scope is activated:
- Function declarations in a scope are hoisted when that scope’s execution context is created. So an inner nested function’s declaration is only hoisted when its parent function is executed, not when the global code first runs.
- Let’s use a concrete example to make this tangible:
Notice that// Global scope processing happens first: outerFunc is hoisted console.log(outerFunc); // Logs the function definition, not undefined function outerFunc() { // When outerFunc runs, its execution context is created—now innerFunc is hoisted here console.log(innerFunc); // Logs the inner function definition function innerFunc() { console.log("Hello from inner!"); } } // If we tried to log innerFunc here in the global scope, it would throw a ReferenceError // console.log(innerFunc); // Uncaught ReferenceError: innerFunc is not defined outerFunc(); // Triggers the processing of outerFunc's scope, and innerFunc's hoistinginnerFuncdoesn’t exist in the global scope at all—its hoisting is confined toouterFunc’s scope, which only gets processed whenouterFuncruns.
A quick side note: Don’t confuse function declarations with function expressions. Function expressions (like const myFunc = function() {}) only have the variable name hoisted, not the function body itself—so you’ll get undefined if you try to access them before their assignment.
To wrap it up:
- The JS engine processes scopes incrementally, not all at once. It only scans and handles declarations for the scope it’s currently executing (or about to execute).
- Hoisting is a per-scope operation, not a full-code sweep. Nested functions’ hoisting happens only when their parent scope is activated during execution.
内容的提问来源于stack exchange,提问作者Deli Sandor




