ES6 let 与 var 的区别:块级作用域详解

作者:代码拾荒

时间:2026-10-22

浏览:307

本文深入解析 ES6 中 let 与 var 的核心差异,重点探讨块级作用域如何解决经典的闭包变量提升陷阱。通过对比示例说明 let 在循环中的独立值特性,并澄清 const 的不可变性限制及浏览器兼容性解决方案,帮助开发者更精准地选择变量声明方式。

文章目录

前言

let 与 var 的作用域差异

在长期的 JavaScript 开发中,我已全面转向使用 ES2015(即 ES6)语法,并青睐其带来的代码优雅性与简洁性。其中最显著的习惯改变是摒弃 var,转而使用 let 和 const。起初我误以为 let 仅是 var 的简单替代品,但实际上 let 提供了更为精细的作用域控制机制。

我大多数时候使用的变量都是用const来声明,因为如果尝试对使用const声明的变量进行修改,将会报错。这可以避免不小心将一个不该修改的常量值修改。但是,我们还是需要可以声明可以被修改的变量,比如在循环里面的计数器,我们需要不断地对改变了加1。可是为什么我们使用let而不是var呢?

根本原因在于 let 提供了块级作用域(block-scoping),相比 var 的函数作用域,它能提供更精细的控制粒度。为直观展示两者差异,以下通过一个经典的前端面试题进行对比分析。

经典闭包陷阱分析

问题:请预测以下代码在控制台的打印结果。


var callbacks = [];
(function() {
 for (var i = 0; i < 5; i++) {
 callbacks.push( function() { return i; } );
 }
})();
console.log(callbacks.map( function(cb) { return cb(); } ));

代码执行一个 for 循环共五次,每次将一个函数推入 callbacks 数组。最终,依次执行 callbacks 数组中的每个函数并打印结果。

新手工程师经过仔细思考后,可能会回答输出结果为 [0, 1, 2, 3, 4],但这实际上落入了 JavaScript 的“变量提升(hoisting)”陷阱。

只有深入理解变量提升机制,才能得出正确答案:[5, 5, 5, 5, 5]。


var callbacks = [];
(function() {
 var i;
 for (i = 0; i < 5; i++) {
 callbacks.push( function() { return i; } );
 }
})();
console.log(callbacks.map( function(cb) { return cb(); } ));

注意:在上述代码中,JavaScript 将变量 i 提升到函数定义的顶部。经过整个 for 循环后,callbacks 数组中存储的五个函数所引用的同一个变量 i 的值已变为 5。因此,最终打印出的所有值均为 5。

let 的解决方案

过去,开发者需借助各种技巧(如立即执行函数)来解决此问题,从而正确返回 [0, 1, 2, 3, 4]。如今,使用 let 即可简洁地解决该问题:


var callbacks = [];
(function() {
 for (let i = 0; i < 5; i++) {
 callbacks.push( function() { return i; } );
 }
})();
console.log(callbacks.map( function(cb) { return cb(); } ));

由于 let 具备块级作用域,使用 let 声明的变量 i 不会被提升到函数顶部。i 的作用域被限制在 for 循环块内,因此每次循环迭代都会创建一个新的独立绑定,从而保留正确的值。

那么,我们是否应该彻底弃用 var 呢?并非如此。如果确实需要变量具有函数作用域,var 仍然具有其存在价值。

常见疑问解答

针对读者提出的两个补充问题,说明如下:

1、const 声明的变量并非完全不可更改。例如:


const myNotQuiteImmutableObject = {
 thisCanBeChanged: "not immutable"
};
myNotQuiteImmutableObject.thisCanBeChanged = "see I changed it.";

然而,使用 const 声明可以防止某些基本类型的重新赋值,例如:


const immutableString = "you can't change me";
immutableString = "D'OH!"; // error

若需实现完全不可变的数据结构,建议使用 Facebook 提供的 Immutable.js 库。

2、老版本浏览器不支持 let。此外,部分较新的浏览器早期版本也未完全支持 let。为解决兼容性问题,可使用 Babel 工具。Babel 允许开发者使用最新的 JavaScript 特性,并将其编译为兼容甚至 IE8 的代码。

原文: Why You Shouldn't Use ‘var' Anymore

译者: Fundebug

为保证文章可读性,本文采用意译而非直译。

总结

以上即为本文的全部内容,希望这些内容能对大家的 JavaScript 学习或工作有所帮助。如有任何疑问,欢迎留言交流,感谢大家对本站的支持。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章