ES6 let 与 var 的区别:块级作用域详解
本文深入解析 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 学习或工作有所帮助。如有任何疑问,欢迎留言交流,感谢大家对本站的支持。
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
JavaScript函数定义的三种方式:声明、表达式与箭头函数
2026-11-05 13:50:55
JavaScript中escape、encodeURI和encodeURIComponent对空格的处理差异
2026-11-05 12:47:23
