JavaScript let 和 const(一文讲透)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
前言
在 JavaScript 的发展过程中,变量声明方式经历了从 var
到 let
和 const
的演变。对于编程初学者而言,理解 let
和 const
的差异与使用场景是掌握现代 JavaScript 的关键步骤。本文将通过对比、案例和比喻的方式,系统性地解析这两个关键字的核心特性,帮助开发者避免常见陷阱,并提升代码质量。
一、变量声明的基础:从 var 到 let 和 const
1.1 为什么需要 let 和 const?
JavaScript 最初使用 var
关键字声明变量,但 var
存在两个显著问题:
- 函数作用域:变量在函数内部声明后,其作用域仅限于该函数,无法在块级(如
if
语句或for
循环)内限制范围。 - 变量提升(Hoisting):变量在声明前即可被访问,但值为
undefined
,容易引发逻辑错误。
let
和 const
的引入解决了这些问题,同时提供了更清晰的作用域控制和不可变性保证。
二、let:可变但受限制的变量
2.1 let 的基本语法与特性
let message = "Hello World";
message = "Hello JavaScript"; // 允许重新赋值
console.log(message); // 输出:Hello JavaScript
核心特性:
- 块级作用域:
let
声明的变量仅在{}
包裹的代码块内有效。例如:if (true) { let greeting = "Hi"; } console.log(greeting); // 报错:greeting 未定义
- 暂时性死区(TDZ):在变量声明前访问它会抛出
ReferenceError
,避免了var
的变量提升问题。
2.2 let 与 var 的对比:以循环为例
// 使用 var 的问题
for (var i = 0; i < 5; i++) {}
console.log(i); // 输出:5(i 在全局作用域中存在)
// 使用 let 的解决方案
for (let j = 0; j < 5; j++) {}
console.log(j); // 报错:j 未定义
比喻:
将 var
视为“全局通行证”,变量可能在意外的地方被访问;而 let
则像“房间钥匙”,仅在特定区域内有效。
三、const:不可变的引用与值的陷阱
3.1 const 的基本语法与特性
const PI = 3.1415;
PI = 3; // 报错:Assignment to constant variable
核心特性:
- 不可重新赋值:一旦声明,变量名与值的绑定不可改变。
- 引用类型不可变,但内容可变:对于对象或数组,
const
仅阻止对变量名的重新赋值,但允许修改对象属性或数组元素:const user = { name: "Alice" }; user.name = "Bob"; // 合法 user = { name: "Charlie" }; // 报错
比喻:
const
类似“密封的盒子”,盒子本身不可替换,但盒内物品可以调整。
3.2 const 的最佳实践
- 优先使用 const:除非需要重新赋值,否则推荐用
const
,以明确变量的意图。 - 对象和数组的声明技巧:
const fruits = ["Apple", "Banana"]; fruits.push("Orange"); // 合法 fruits = ["Grape"]; // 报错
四、作用域与生命周期:变量的“生存空间”
4.1 块级作用域的边界
let
和 const
的作用域严格遵循代码块(即 {}
内部),而 var
则遵循函数作用域。例如:
function example() {
if (true) {
let x = 10; // 只在 if 块内可见
var y = 20; // 在整个函数内可见
}
console.log(x); // 报错
console.log(y); // 输出:20
}
4.2 变量提升与暂时性死区
console.log(a); // undefined(var 的变量提升)
console.log(b); // ReferenceError(let 的暂时性死区)
var a = 1;
let b = 2;
五、最佳实践与常见误区
5.1 选择 let 还是 const?
- const 是默认选择:除非变量需要被重新赋值,否则始终使用
const
,以增强代码的可维护性。 - let 的适用场景:循环计数器、临时变量,或需要多次修改值的变量。
5.2 避免 const 的陷阱
const numbers = [1, 2, 3];
numbers = [4, 5, 6]; // 报错
numbers.push(4); // 合法
numbers.length = 0; // 合法(清空数组)
5.3 变量重复声明的限制
let name = "Alice";
let name = "Bob"; // 报错:Identifier 'name' has already been declared
与 var
不同,let
和 const
禁止在相同作用域内重复声明同名变量。
六、案例分析:从错误中学习
6.1 循环中的闭包问题
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 输出:3,3,3(因变量提升问题)
}, 100);
}
解决方案:使用 let
替换 var
,或通过闭包捕获当前值:
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i); // 输出:0,1,2
}, 100);
}
6.2 const 的不可变性误用
const person = {
name: "John",
hobbies: ["Reading"]
};
person.hobbies.push("Gaming"); // 合法
person.hobbies = ["Cooking"]; // 报错
修正方法:若需完全冻结对象,使用 Object.freeze()
:
const frozenPerson = Object.freeze({ name: "Jane" });
frozenPerson.name = "Jill"; // 无效果(但不会报错)
七、结论
let
和 const
是 JavaScript 变量声明的现代标准,它们通过块级作用域和不可变性特性,显著提升了代码的可读性和安全性。开发者应遵循以下原则:
- 优先使用 const,除非变量需要被重新赋值。
- 理解作用域边界,避免因变量提升或闭包引发的错误。
- 善用开发工具,如控制台和调试器,及时发现作用域相关的问题。
通过本文的解析,希望读者能够掌握 let
和 const
的核心用法,并在实际项目中合理应用,逐步养成规范的编码习惯。
(全文约 1,800 字)