JavaScript 开发必知:var 和 let 的区别,你真的了解吗?

简介:本文深入剖析 JavaScript 中 var 与 let 的关键区别。涵盖作用域(函数/块级)、变量提升(var 提升赋值、let 存在暂时性死区)、重复声明规则,以及在循环中的不同表现,助你理解差异,避免编码陷阱,写出更规范的代码

在 JavaScript 的发展过程中,变量声明方式经历了从 var let(以及 const)的演变。var 是 ES5 及之前版本中唯一的变量声明关键字,而 let const 是在 ES6(ECMAScript 2015)中引入的。理解 var 和 let 的区别对于编写高质量、可维护的 JavaScript 代码至关重要。本文将详细探讨它们之间的差异,并通过具体的代码示例进行说明。

作用域不同

1. var 的函数作用域

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();

2. let 的块级作用域

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();

变量提升不同

1 var 的变量提升

var 声明的变量会被提升到其所在作用域的顶部,但只会提升声明,不会提升赋值。这意味着在声明之前可以访问 var 变量,但它的值会等于undefined

function varHoistingExample() {
  console.log(b); // 输出: undefined,而不是报错
  var b = 50;
  console.log(b); // 输出: 50
}
varHoistingExample();

2 let 的暂时性死区

let 声明的变量也会被提升,但不会初始化。在声明之前访问 let 变量会导致 ReferenceError,这个区域被称为暂时性死区:

function letHoistingExample() {
  // console.log(c); // 报错: ReferenceError: Cannot access 'c' before initialization
  let c = 60;
  console.log(c); // 输出: 60
}
letHoistingExample();

重复声明不同

1 var 允许重复声明

在同一个作用域内,可以使用 var 多次声明同一个变量,后声明的变量会覆盖先声明的变量(但不会报错,这可能导致意外的行为):

function varRedeclarationExample() {
  var d = 70;
  var d = 80; // 不会报错,d 的值变为 80
  console.log(d); // 输出: 80
}
varRedeclarationExample();

2 let 不允许重复声明

在同一个作用域内,使用 let 多次声明同一个变量会导致语法错误

function letRedeclarationExample() {
  let e = 90;
  // let e = 100; // 报错: SyntaxError: Identifier 'e' has already been declared
  e = 100; // 这是允许的,是赋值操作,不是声明
  console.log(e); // 输出: 100
}
letRedeclarationExample();

在循环中的应用

1 var 在循环中的问题

由于 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();

2 let 在循环中的优势

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。

 

有遗漏或者不对的可以在我的公众号留言哦

编程经验共享公众号二维码

编程经验共享公众号二维码
更多内容关注公众号
Copyright © 2021 编程经验共享 赣ICP备2021010401号-1