likes
comments
collection
share

深入理解 var、let、和 const

作者站长头像
站长
· 阅读数 13

在前端面试中,有一个经常遇到的问题:“请你谈谈 var、let 及 const 的区别?”。对于这个问题大多数人都能回答一些,但在细节上却又容易模糊不清。本文将带大家一起理解他们之间的区别。

一、作用域

  1. var:使用 var 声明的变量具有函数作用域,在整个函数内部都可见。如果在函数内部使用 var 声明的变量,则该变量仅在函数内部有效,在函数外部无法访问。
  2. letconst:使用 let 和 const 声明的变量具有块级作用域,只在当前代码块内有效。代码块可以是函数、循环或条件语句等。

ES6 引入了块级作用域关键字来解决变量提升带来的问题。使用 letconst 声明的变量会形成一个封闭的块级作用域,在该作用域中的变量不会影响作用域外部的变量。

function foo() {
  var x = 10
  if (true) {
    var x = 20
    console.log(x) // 输出 20
  }
  console.log(x) // 输出 20
}

foo()
console.log(x) // ReferenceError: x is not defined
function foo() {
  let x = 10
  if (true) {
    let x = 20
    console.log(x) // 输出 20
  }
  console.log(x) // 输出 10
}

foo()
console.log(x) // ReferenceError: x is not defined

二、可变性

  1. var 声明的变量可以重新声明,但是 letconst 不可以重新声明。
  2. varlet 声明的变量是可修改的,可以随时重新赋值。但是 let 声明的变量只能在其作用域范围内重新赋值。
  3. 使用 const 声明的变量是不可变的,即一旦赋值后就不能再修改。尝试重新赋值给 const 声明的常量会导致错误,但当用 const 声明对象时,可以更新对象的属性。
var say = 'say Hi';
var say = 'say Hello'; 

let name = 'xiaoming';
let name = 'xiaohua'; // SyntaxError: Identifier 'name' has already been declared
let say = 'say Hi';
say = 'say Hello'; 

const user = { name: 'xiaoming' };
user.name = 'xiaohua';

const name = 'xiaoming';
name = 'xiaohua'; // TypeError: Assignment to constant variable.

三、变量提升

变量提升是 JavaScript 中的一种行为,指的是在代码执行之前,变量声明和函数声明会被提升到当前作用域的顶部。

  1. 函数提升优先于变量提升。函数声明整体地被提升到作用域顶部,而变量声明只有声明本身会被提升,赋值操作仍然保留在原位置。
  2. 对于使用 letconst 声明的变量,它们也会被提升到它们所在作用域的顶部。但由于存在暂时性死区,如果在变量声明之前访问这些变量,会导致报错。
  3. 使用 var 声明的变量,在被提升到作用域顶部时会被赋值为 undefined ,而使用 letconst 声明的变量不会被初始化。

需要注意的是,如果有多条相同名称的变量声明,只会提升其中的一条声明,后续的声明会被忽略,不会影响已经提升的声明。

function foo() {
  console.log(bar) // function bar() {}
  var bar = 1
  function bar() {}
}

foo()

由于函数提升优先级大于变量提升,所以 var bar = 1 可以看成 bar = 1,var 声明可以忽略。

function foo() {
  function bar() {}
  console.log(bar)
  bar = 1
}

四、暂时性死区

暂时性死区指的是在代码的编译阶段,使用 letconst 声明的变量会在当前代码块中创建一个暂时性死区。在声明之前访问这些变量会引发引用错误(案例中的变量 a)。

当执行到调用还未声明的代码时产生的才会产生错误,编译分析阶段不会报错。

同时,对于其他未声明的变量(案例中的变量 bc),在当前代码块作用域内部如果引用这些变量,JavaScript 会向上级作用域链查找这些变量。它会一直向上查找,直到找到该变量或者到达全局作用域。

var a = 1
var b = 2
let c = 3
function foo() {
  console.log(b) // 2
  console.log(c) // 3
  console.log(a) // ReferenceError: Cannot access 'a' before initialization
  let a = 11
}

foo()

总结

在使用JavaScript中的变量声明关键字时,需要注意变量提升、块级作用域以及常量声明的限制。了解这些知识点,可以帮助你避免一些常见的错误,有助于编写更健壮和可维护的代码。

往期文章推荐: