深入理解 var、let、和 const

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

一、作用域

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

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

javascript 复制代码
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
javascript 复制代码
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 声明对象时,可以更新对象的属性。
javascript 复制代码
var say = 'say Hi';
var say = 'say Hello'; 

let name = 'xiaoming';
let name = 'xiaohua'; // SyntaxError: Identifier 'name' has already been declared
javascript 复制代码
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 声明的变量不会被初始化。

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

javascript 复制代码
function foo() {
  console.log(bar) // function bar() {}
  var bar = 1
  function bar() {}
}

foo()

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

javascript 复制代码
function foo() {
  function bar() {}
  console.log(bar)
  bar = 1
}

四、暂时性死区

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

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

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

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

往期文章推荐:

相关推荐
kyriewen29 分钟前
白宫直接给 OpenAI 下了限制令,GPT-5.6 不能随便放出来了
前端·javascript·面试
未秃头的程序猿5 小时前
Java 26正式发布!这3个新特性,让代码量直接减半
java·后端·面试
默_笙5 小时前
🍞 我用 CSS 画了一个会转的 3D 立方体,同事以为我学了 Three.js(这节课真的很神奇,我很喜欢)
javascript
sarasuki6 小时前
JavaScript的对象、new的机制与原型包装类
javascript·后端
weedsfly6 小时前
JavaScript 事件流:彻底搞懂捕获、冒泡与事件委托
前端·javascript·react.js
AI人工智能_电脑小能手6 小时前
【大白话说Java面试题 第125题】【并发篇】第25题:说说 Java 线程的中断机制
java·后端·面试
candyTong7 小时前
阿里开源 AI Code Review 工具:ocr review 的执行链路解析
javascript·后端·架构
铁皮饭盒7 小时前
TypeBox 比 Zod.js 校验 快10倍, 还兼容AI 工具调用, 他做对了什么?
前端·javascript·后端
To_OC16 小时前
从一次栈溢出报错说起,我把递归彻底扒明白了
javascript·算法·程序员
kyriewen18 小时前
面试官问你:“AI 能写 80% 的代码了,公司为什么还需要你?”
前端·javascript·面试