什么是变量提升
What is hoisting
一句话:编译阶段引擎会先扫一遍, 把声明登记到作用域里, 所以「在声明之前引用」不一定报错 ——但只提升声明,不提升赋值。
四种情况分清就够答:
| 声明前访问的结果 | |
|---|---|
| 函数声明 | 整个函数都能用(可以直接调用) |
var | undefined |
let / const | 抛 ReferenceError(TDZ) |
class | 抛 ReferenceError(也有 TDZ) |
「let 不提升」是个常见错误说法。它确实提升了—— 否则内层的 let x不会遮蔽外层的 x。 只是它被标成「未初始化」,访问就抛错。能纠正这个说法很加分。
会追问:「函数声明和函数表达式呢?」——function f(){} 整体提升;var f = function(){}只提升 f(值是 undefined), 提前调用会得到TypeError: f is not a function。注意这两个报错不一样, 这个细节常用来分辨背没背过。
In one line: during compilation the engine scans the code first and registers the declarations in the scope, so referring to something before its line does not always throw — but only the declaration is hoisted, never the assignment.
Four cases; keeping them apart is enough:
| What you get before the declaration | |
|---|---|
| Function declaration | Usable throughout (you can call it) |
var | undefined |
let / const | throws ReferenceError (TDZ) |
class | throws ReferenceError (a TDZ as well) |
“let is not hoisted” is a common mistake. It is hoisted — otherwise an inner let x would not shadow an outer x. It is just marked uninitialised, so reading it throws. Correcting this scores well.
Follow-up: “What about function declarations against function expressions?” — function f(){} is hoisted whole; var f = function(){} hoists only f (whose value is undefined), so calling it early gives you TypeError: f is not a function. Note the two errors are different — that detail is how they tell recitation from understanding.