news 2026/3/21 10:14:11

ES6 let与const变量声明:完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ES6 let与const变量声明:完整指南

varconst:现代 JavaScript 变量声明的进化之路

你有没有在调试时遇到过这样的困惑——明明还没声明一个变量,却能访问到它,值还是undefined?或者在一个循环里绑定了多个事件回调,结果它们全都输出同一个值?

这些“诡异”的行为,根源往往就藏在 JavaScript 的变量声明机制中。而这一切,在 ES6 引入letconst之后,彻底改变了。

今天我们就来深入聊聊这两个看似简单、实则影响深远的关键字,看看它们是如何重塑我们写 JavaScript 的方式的。


为什么我们需要新的变量声明?

在 ES6 之前,JavaScript 只有一个正式的变量声明方式:var

console.log(name); // undefined var name = "Alice";

这段代码不会报错,但结果可能让你一头雾水。变量被“提升”了——即声明被移到作用域顶部,但赋值仍保留在原地。于是你就得到了一个“存在但未初始化”的状态。

更麻烦的是作用域问题:

for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); } // 输出:3, 3, 3

所有异步回调共享的是同一个i,因为var是函数级作用域,而不是按{}块隔离。这在闭包场景下极易引发 bug。

这些问题促使 TC39 推出了新的解决方案:letconst


let:让变量回归逻辑直觉

它解决了什么?

  • 块级作用域let把变量绑定到最近的一对{}中。
  • 暂时性死区(TDZ):不再允许先使用后声明。
  • 禁止重复定义:避免意外覆盖。

来看个例子:

{ let message = "Hello"; } console.log(message); // ❌ ReferenceError

这个错误反而是好事——它暴露了逻辑错误,而不是默默给你一个undefined

再看经典的循环问题:

for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 100); } // 输出:0, 1, 2 ✅

神奇吗?其实不。每次迭代都会创建一个新的词法环境,每个i都是独立绑定的。这是引擎自动帮你做了闭包隔离,无需手动 IIFE。

TDZ 是什么?

console.log(x); // ❌ Cannot access 'x' before initialization let x = 10;

虽然语法上说“let也会提升”,但它进入了一个叫“暂时性死区”的区域——从作用域开始到实际声明语句之间,该变量不可用。这种设计强制开发者遵循“先声明后使用”的良好习惯。

还有哪些细节值得注意?

  • 在全局作用域中用let声明的变量,不会挂在window上(浏览器),避免污染全局对象。
  • 同一作用域内不能重复声明:
let user = "Tom"; let user = "Jerry"; // SyntaxError

这一点比var严格得多,也安全得多。


const:不只是“常量”,更是编程思维的转变

很多人以为const是定义“不可变的值”,但实际上它定义的是“不可变的绑定”。

什么意思?

const PI = 3.14159; PI = 3.14; // ❌ TypeError: Assignment to constant variable.

基本类型没问题,重新赋值直接抛错。

但对象呢?

const user = { name: "Bob" }; user.name = "Alice"; // ✅ 允许! user = {}; // ❌ 不允许!

看到了吗?const锁住的是“user指向这个对象”这件事,而不是对象本身的内容。你可以修改属性,但不能把user指向另一个新对象。

这说明了一点:const提供的是引用不变性,不是深冻结

如果你真的需要完全不可变的对象,得配合Object.freeze()

const config = Object.freeze({ apiBase: '/api', timeout: 5000, headers: { 'Content-Type': 'application/json' } }); config.timeout = 6000; // ❌ 无声失败(严格模式下报错) config.headers['X-Token'] = 'xxx'; // ⚠️ 注意:嵌套对象仍可变!

小贴士:Object.freeze()是浅冻结。如果要深层冻结,需要递归处理或使用库如deep-freeze


let/constvsvar:一场作用域革命

特性varletconst
作用域函数级块级块级
提升行为提升并初始化为undefined提升但处于 TDZ提升但处于 TDZ
可重复声明允许禁止禁止
绑定全局对象是(如window.x
是否必须初始化
是否允许重新赋值

关键差异总结一句话:
var是宽松且容易出错的;letconst是严谨且可预测的。


实战中的最佳实践

1. 默认用const,只在必要时降级为let

这是一个被广泛采纳的原则。问问自己:这个变量后面还会被重新赋值吗?

const apiUrl = 'https://api.example.com'; const users = await fetchUsers(); let retries = 0; while (retries < 3) { try { return await fetchData(); } catch { retries++; // 必须改变值 → 用 let } }

这样做的好处:
- 明确表达意图:“我本不想改它”
- 减少意外重写的风险
- 更利于静态分析和性能优化(V8 引擎会对const做更多假设)

2. 在模块配置中大量使用const

现代前端项目高度依赖配置驱动:

const API_VERSION = 'v2'; const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB const SUPPORTED_FORMATS = ['jpg', 'png', 'gif']; /** * 创建请求实例 */ const request = axios.create({ baseURL: `${API_ROOT}/${API_VERSION}`, timeout: REQUEST_TIMEOUT, });

这些值一旦设定就不应变动,用const正合适。

3. 函数表达式优先用const

const handleClick = () => { console.log('Button clicked'); }; const validateForm = function() { // ... };

防止函数引用被意外覆盖。比起function声明,这种方式更能体现“函数即值”的理念。

4. 循环中优先使用let

即使你不打算修改循环变量,也推荐用let而非var

for (let i = 0; i < items.length; i++) { const item = items[i]; setTimeout(() => console.log(item), 100); }

不仅能避免闭包陷阱,还能让i的生命周期控制在循环体内。


工程化建议:用工具守住底线

光靠自觉不够,要用 ESLint 把规范固化下来。

推荐启用以下规则:

{ "rules": { "no-var": "error", // 禁止使用 var "prefer-const": "warn", // 如果从未重新赋值,提示改用 const "const-spacing": ["error", "both"] // const 前后空格一致性 } }

加上"env": { "es6": true }或使用eslint:recommended,就能在开发阶段提前发现问题。

配合 Prettier 和编辑器集成,团队协作效率会大幅提升。


写在最后:不仅仅是语法糖

letconst看似只是多了两个关键字,实则是 JavaScript 成熟化的标志之一。

它们推动我们从“随意声明”走向“精确控制”,从“动态混乱”迈向“结构清晰”。更重要的是,它们引导我们形成一种新的编程哲学:

尽可能减少可变性,明确变量生命周期,增强代码自文档能力。

当你开始习惯写const x = ...并只在真正需要时才改为let,你就已经踏上了写出更健壮、更易维护代码的道路。

而这,正是现代 JavaScript 开发的第一课。

你在项目中已经全面转向let/const了吗?有没有遇到过因为var导致的坑?欢迎在评论区分享你的故事。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/21 0:00:28

mathtype COM接口调用实现公式提取供TTS朗读

MathType COM接口调用实现公式提取供TTS朗读 在教育信息化和无障碍阅读的浪潮中&#xff0c;一个看似简单却长期被忽视的问题浮出水面&#xff1a;如何让视障用户“听”懂数学公式&#xff1f;对于普通人来说&#xff0c;Word文档中的 $ E mc^2 $ 只是一个符号组合&#xff1b…

作者头像 李华
网站建设 2026/3/14 5:10:08

GLM-TTS批量推理教程:使用JSONL文件自动化生成大量音频内容

GLM-TTS批量推理实践&#xff1a;用JSONL高效生成大规模语音内容 在有声书、在线教育和智能客服等场景中&#xff0c;我们常常面临一个共同挑战&#xff1a;如何快速、一致地为成百上千条文本生成高质量的语音&#xff1f;传统TTS系统虽然能“说话”&#xff0c;但每次只能处理…

作者头像 李华
网站建设 2026/3/19 4:22:59

CSDN官网教程:手把手教你搭建Fun-ASR语音识别平台

Fun-ASR语音识别平台搭建与工程实践深度解析 在远程办公、智能会议和自动化内容处理日益普及的今天&#xff0c;如何高效地将语音转化为准确可读的文字&#xff0c;已成为企业和开发者面临的核心挑战之一。传统语音识别系统往往依赖复杂的多模块拼接架构&#xff0c;部署门槛高…

作者头像 李华
网站建设 2026/3/18 2:02:52

Multisim下载速度慢?Windows网络优化技巧通俗解释

Multisim下载卡成幻灯片&#xff1f;别急&#xff0c;这4招让Windows网络“原地起飞”你有没有过这样的经历&#xff1a;想装个Multisim做电路仿真&#xff0c;点开NI官网的下载链接&#xff0c;进度条慢得像在放幻灯片——1小时才下完一半安装包&#xff0c;中间还断了两次&am…

作者头像 李华
网站建设 2026/3/14 7:25:34

图解说明Multisim主数据库访问受限的根源

图解说明Multisim主数据库访问受限的根源在电子工程教学与产品开发中&#xff0c;Multisim是一款广受信赖的电路仿真工具。它强大的元件库和直观的界面让从学生到工程师都能快速搭建并验证电路设计。然而&#xff0c;几乎每个长期使用者都曾遭遇过一个令人头疼的问题&#xff1…

作者头像 李华