简介:本文深入剖析 JavaScript 中 var 与 let 的关键区别。涵盖作用域(函数/块级)、变量提升(var 提升赋值、let 存在暂时性死区)、重复声明规则,以及在循环中的不同表现,助你理解差异,避免编码陷阱,写出更规范的代码
在 JavaScript 的发展过程中,变量声明方式经历了从 var 到 let(以及 const)的演变。var 是 ES5 及之前版本中唯一的变量声明关键字,而 let 和 const 是在 ES6(ECMAScript 2015)中引入的。理解 var 和 let 的区别对于编写高质量、可维护的 JavaScript 代码至关重要。本文将详细探讨它们之间的差异,并通过具体的代码示例进行说明。
var 声明的变量具有函数作用域(function scope),这意味着在函数内部声明的变量在整个函数内部都是可访问的,无论变量是在哪里声明的。如果在函数外部声明 var 变量,它将具有全局作用域。
function varExample() {
if (true) {
var x = 10;
}
console.log(x); // 输出: 10,因为 var 是函数作用域
}
varExample();
// 全局作用域中的 var
var y = 20;
function anotherFunction() {
console.log(y); // 输出: 20,因为 y 是全局变量
}
anotherFunction();
let 声明的变量具有块级作用域(block scope),块级作用域由一对大括号 {} 定义,例如 if 语句、for 循环、while 循环等。在块级作用域内声明的 let 变量仅在该块及其子块中可访问。
function letExample() {
if (true) {
let z = 30;
console.log(z); // 输出: 30
}
// console.log(z); // 报错: ReferenceError: z is not defined,因为 z 是块级作用域变量
}
letExample();
// 全局作用域中的 let(不推荐,应尽量减少全局变量)
let a = 40;
function yetAnotherFunction() {
console.log(a); // 输出: 40
}
yetAnotherFunction();
var 声明的变量会被提升到其所在作用域的顶部,但只会提升声明,不会提升赋值。这意味着在声明之前可以访问 var 变量,但它的值会等于undefined
function varHoistingExample() {
console.log(b); // 输出: undefined,而不是报错
var b = 50;
console.log(b); // 输出: 50
}
varHoistingExample();
let 声明的变量也会被提升,但不会初始化。在声明之前访问 let 变量会导致 ReferenceError,这个区域被称为暂时性死区:
function letHoistingExample() {
// console.log(c); // 报错: ReferenceError: Cannot access 'c' before initialization
let c = 60;
console.log(c); // 输出: 60
}
letHoistingExample();
在同一个作用域内,可以使用 var 多次声明同一个变量,后声明的变量会覆盖先声明的变量(但不会报错,这可能导致意外的行为):
function varRedeclarationExample() {
var d = 70;
var d = 80; // 不会报错,d 的值变为 80
console.log(d); // 输出: 80
}
varRedeclarationExample();
在同一个作用域内,使用 let 多次声明同一个变量会导致语法错误
function letRedeclarationExample() {
let e = 90;
// let e = 100; // 报错: SyntaxError: Identifier 'e' has already been declared
e = 100; // 这是允许的,是赋值操作,不是声明
console.log(e); // 输出: 100
}
letRedeclarationExample();
由于 var 是函数作用域,在循环中声明的 var 变量在整个函数内都是可访问的,这可能导致一些意外的行为。
function varInLoopExample() {
var funcs = [];
for (var i = 0; i < 3; i++) {
funcs.push(function() {
console.log(i);
});
}
funcs[0](); // 输出: 3
funcs[1](); // 输出: 3
funcs[2](); // 输出: 3
// 因为循环结束后 i 的值是 3,所有函数都引用了同一个 i 变量
}
varInLoopExample();
let 的块级作用域可以解决上述问题,每次循环都会创建一个新的块级作用域,每个函数都引用了自己作用域内的 i 变量。
function letInLoopExample() {
var funcs = [];
for (let j = 0; j < 3; j++) {
funcs.push(function() {
console.log(j);
});
}
funcs[0](); // 输出: 0
funcs[1](); // 输出: 1
funcs[2](); // 输出: 2
// 每次循环都创建了一个新的块级作用域,每个函数引用了自己作用域内的 j 变量
}
letInLoopExample();
在现代 JavaScript 开发中,推荐优先使用 let 对于不会重新赋值的变量)来声明变量,因为它们提供了更严格的作用域规则,有助于减少代码中的错误和意外行为。只有在需要兼容旧版浏览器或特定场景下才考虑使用 var。
有遗漏或者不对的可以在我的公众号留言哦