⭐ 推荐:社区规则条款 V1.0

js var let const 三者有什么区别

chinaz
chinaz 初级会员萌新站长
发布于 2026-10-16 23:17 ·2 浏览 ·0 回复
内容摘要

var 为函数作用域、存在变量提升且可重复声明,let 和 const 为块级作用域、有暂时性死区且不可重复声明,const 还要求声明时立即赋值并禁止重新赋值;日常编码默认用 const,需重新赋值时用 let,var 仅见于旧代码维护。

**结论:var 是函数作用域、存在变量提升且默认值为 undefined、允许重复声明;let 和 const 是块级作用域、有暂时性死区(TDZ,声明前访问直接报错)、不允许重复声明;const 额外要求声明时立即赋值,且不能再重新赋值。** 日常写代码的默认选择是 const,需要重新赋值时才换成 let,var 基本只在维护老代码时才会见到。

var、let、const 最核心的区别是什么?

一句话:作用域范围、能否重复声明、能否重新赋值,这三条就区分完了。

维度varletconst
作用域函数作用域块级作用域块级作用域
变量提升提升并初始化为 undefined提升但未初始化(TDZ)提升但未初始化(TDZ)
重复声明允许报错报错
必须初始化否否是
重新赋值可以可以报错(TypeError)
挂到 window全局声明时会不会不会

「块级作用域」指 {}、if、for 这类大括号范围;「函数作用域」指只有函数体才形成边界。具体看这段代码:

{ var a = 1; let b = 2; const c = 3; }
console.log(a); // 1
console.log(b); // ReferenceError: b is not defined

let/const 在 ES6(ECMAScript 2015,2015 年 6 月发布)引入,这也是它们和 var 分家的起点。

什么是变量提升和暂时性死区(TDZ)?

结论:var 在声明前访问得到 undefined,let/const 在声明前访问直接抛 ReferenceError,这段「声明语句之前、作用域之内」的区间就叫暂时性死区。

console.log(x); // undefined
var x = 1;

console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 2;

很多人以为 let 没有提升,其实引擎在进入块时就已经为 y 分配了空间,只是不初始化,直到执行到声明那一行才填值。区别在于 var 被「提前初始化成 undefined」,所以访问不报错但拿不到值——这正是老代码里 undefined 报错的常见来源。TDZ 的好处是把「用错变量」从静默的 undefined 变成显式报错。

var 和 let 在 for 循环里有什么区别?

结论:for (var i = 0; ...) 全局只有一个 i,循环结束后 i 等于循环次数;for (let i = 0; ...) 每轮迭代生成一个新的 i 绑定,因此 setTimeout 能拿到 0、1、2。

for (var i = 0; i < 3; i++) setTimeout(() => console.log(i)); // 3 3 3
for (let j = 0; j < 3; j++) setTimeout(() => console.log(j)); // 0 1 2

这是面试和实际调试中出现频率最高的差异。ES6 之前要修这个问题,得用 IIFE(立即执行函数)把 i 作为参数包一层,现在直接用 let 就够了。

const 声明的对象为什么还能改属性?

结论:const 锁的是「变量与值之间的绑定」,不是值本身。对象是引用类型,只要引用没换,改内部属性完全合法。

const obj = { a: 1 };
obj.a = 2;        // 合法
obj.b = 3;        // 合法
obj = {};         // TypeError: Assignment to constant variable.

const arr = [1, 2];
arr.push(3);      // 合法

如果确实要连属性一起锁死,用 Object.freeze(obj)(浅冻结)或 Object.freeze 加递归实现深冻结;注意冻结后严格模式下赋值会报 TypeError,非严格模式静默失败。另外 const 声明必须带初始值,const x; 会直接抛 SyntaxError: Missing initializer in const declaration。

实际开发中该怎么选?

结论:默认 const,需要重新赋值时改 let,除非在改一个已经大量使用 var 的老文件,否则不要新写 var。

三条可执行规则:

  1. 能用 const 就用 const,包括对象、数组、函数表达式,因为它能防止误赋值。
  2. 只有循环计数器、累加器这类会被重新赋值的变量用 let。
  3. 打开 ESLint 的 prefer-const 和 no-var 规则,让工具替你做这件事。

需要注意的是,var 在浏览器非模块脚本的顶层声明会挂到 window 上(var a = 1 后 window.a === 1),let/const 不会,所以用 let 声明同名变量不会污染全局对象。这个差别在老库和现代打包代码混用时经常成为排查问题的关键点。

回到开头那句话:作用域、TDZ、重复声明、重新赋值,四个点记住了,var/let/const 的区别就再也不会混。

本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-2207.html
转载请注明出处,版权归原作者所有。
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 0

还没有回复,来抢沙发~