DrillLab
第 20 / 105 道20 / 105 · #282

var、let、const 的区别

What is the difference between var, let and const

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

一句话:var 是函数作用域、会提升成undefined、能重复声明;let / const 是块作用域、 有 TDZ、不能重复声明;const 还不能重新赋值。

varletconst
作用域函数{}
声明前访问undefinedReferenceErrorReferenceError
重复声明可以不行不行
重新赋值可以可以不行
挂到 window顶层会挂不挂不挂

TDZ(暂时性死区)let / const「从块开始到声明那一行」之间的区域。 变量确实被提升了,但被标记为「还不能用」, 所以访问会抛错而不是给 undefined。 这是刻意设计的 —— 让错误早暴露。

会追问:const 的对象能改属性吗?」——const 锁的是绑定(这个名字不能再指向别的东西), 不是。 想冻结内容用 Object.freeze()

还会追问循环那道经典题——for (var i…)setTimeout 会打出三个 3,let 会打出 0 1 2。 因为 let每次迭代都创建一个新的绑定, 而 var 全程只有一个 i。 这题和闭包(#298)连着考。

In one line: var is function-scoped, hoists to undefined and can be redeclared; let / const are block-scoped, have a TDZ and cannot be redeclared; const on top of that cannot be reassigned.

varletconst
ScopeFunctionBlock {}Block
Read before the declarationundefinedthrows ReferenceErrorthrows ReferenceError
RedeclareAllowedNoNo
ReassignAllowedAllowedNo
Lands on windowYes at top levelNoNo

The TDZ (temporal dead zone) is the stretch between the start of the block and the let / const line itself. The variable really is hoisted, but flagged as “not usable yet”, so reading it throws instead of handing you undefined. That is deliberate — it makes mistakes surface early.

Follow-up: “Can you change the properties of a const object?” — yes. const locks the binding (the name cannot point at anything else), not the value. To freeze the contents, use Object.freeze().

Another follow-up — the classic loop question: for (var i…) with setTimeout prints three 3s; let prints 0 1 2. Because let creates a fresh binding on every iteration, while var has one single i the whole way through. This gets asked together with closures (#298).

JavaScript三个必背的例子Three examples worth memorising示意Illustrative
1// 经典循环题
2for (var i = 0; i < 3; i++) setTimeout(() => console.log(i));
3// 3 3 3 —— 只有一个 i,回调跑的时候它已经是 3
4
5for (let j = 0; j < 3; j++) setTimeout(() => console.log(j));
6// 0 1 2 —— 每次迭代一个新的 j
7
8// TDZ
9console.log(a); // undefined var 提升成 undefined
10var a = 1;
11
12console.log(b); // ReferenceError: Cannot access 'b' before initialization
13let b = 1;
14
15// const 锁绑定,不锁内容
16const o = { n: 1 };
17o.n = 2; // ✓ 可以
18o = { n: 3 }; // ✗ TypeError: Assignment to constant variable
1// The classic loop question
2for (var i = 0; i < 3; i++) setTimeout(() => console.log(i));
3// 3 3 3 —— there is only one i, and by the time the callbacks run it is 3
4
5for (let j = 0; j < 3; j++) setTimeout(() => console.log(j));
6// 0 1 2 —— every iteration gets a new j
7
8// TDZ
9console.log(a); // undefined var is hoisted as undefined
10var a = 1;
11
12console.log(b); // ReferenceError: Cannot access 'b' before initialization
13let b = 1;
14
15// const locks the binding, not the contents
16const o = { n: 1 };
17o.n = 2; // ✓ allowed
18o = { n: 3 }; // ✗ TypeError: Assignment to constant variable