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 的发展过程中,变量声明方式经历了从 varletconst 的演变。对于编程初学者而言,理解 letconst 的差异与使用场景是掌握现代 JavaScript 的关键步骤。本文将通过对比、案例和比喻的方式,系统性地解析这两个关键字的核心特性,帮助开发者避免常见陷阱,并提升代码质量。


一、变量声明的基础:从 var 到 let 和 const

1.1 为什么需要 let 和 const?

JavaScript 最初使用 var 关键字声明变量,但 var 存在两个显著问题:

  1. 函数作用域:变量在函数内部声明后,其作用域仅限于该函数,无法在块级(如 if 语句或 for 循环)内限制范围。
  2. 变量提升(Hoisting):变量在声明前即可被访问,但值为 undefined,容易引发逻辑错误。

letconst 的引入解决了这些问题,同时提供了更清晰的作用域控制和不可变性保证。


二、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 块级作用域的边界

letconst 的作用域严格遵循代码块(即 {} 内部),而 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 不同,letconst 禁止在相同作用域内重复声明同名变量。


六、案例分析:从错误中学习

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"; // 无效果(但不会报错)  

七、结论

letconst 是 JavaScript 变量声明的现代标准,它们通过块级作用域和不可变性特性,显著提升了代码的可读性和安全性。开发者应遵循以下原则:

  1. 优先使用 const,除非变量需要被重新赋值。
  2. 理解作用域边界,避免因变量提升或闭包引发的错误。
  3. 善用开发工具,如控制台和调试器,及时发现作用域相关的问题。

通过本文的解析,希望读者能够掌握 letconst 的核心用法,并在实际项目中合理应用,逐步养成规范的编码习惯。


(全文约 1,800 字)

最新发布