DrillLab
第 31 / 105 道31 / 105 · #296

什么是变量提升

What is hoisting

先自己答,再往下看Answer it yourself first

一句话:编译阶段引擎会先扫一遍, 把声明登记到作用域里, 所以「在声明之前引用」不一定报错 ——但只提升声明,不提升赋值

四种情况分清就够答:

声明前访问的结果
函数声明整个函数都能用(可以直接调用)
varundefined
let / constReferenceError(TDZ)
classReferenceError(也有 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 declarationUsable throughout (you can call it)
varundefined
let / constthrows ReferenceError (TDZ)
classthrows 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.

JavaScript四种提升行为Four hoisting behaviours示意Illustrative
1console.log(fn()); // "ok" 函数声明整体提升
2console.log(v); // undefined var 提升成 undefined
3console.log(l); // ReferenceError(TDZ)
4
5function fn() { return "ok"; }
6var v = 1;
7let l = 2;
8
9// 两种「不是函数」的报错要分清
10foo(); // TypeError: foo is not a function
11var foo = function () {};
12
13bar(); // ReferenceError: Cannot access 'bar' ...
14let bar = function () {};
1console.log(fn()); // "ok" a function declaration is hoisted whole
2console.log(v); // undefined var is hoisted as undefined
3console.log(l); // ReferenceError (TDZ)
4
5function fn() { return "ok"; }
6var v = 1;
7let l = 2;
8
9// Tell the two "not a function" errors apart
10foo(); // TypeError: foo is not a function
11var foo = function () {};
12
13bar(); // ReferenceError: Cannot access 'bar' ...
14let bar = function () {};