摘要:本文系统对比了 JavaScript 中var、let和const三种变量声明方式的核心差异。从作用域、变量提升与暂时性死区、重复声明规则以及赋值规则四个维度展开,详细阐述了var的函数作用域、变量提升、允许重复声明和灵活赋值特性,以及let/const的块级作用域、暂时性死区、禁止重复声明等 ES6 新规范。重点强调了const作为常量的初始化要求和不可变性规则。全文结合代码示例和图解,旨在帮助开发者深入理解并正确选用变量声明关键字。
目录
- 一、作用域不同
- 1. var:函数作用域
- 2. let:块级作用域
- 3. const:块级作用域
- 二、变量提升与暂时性死区
- 1. var:存在变量提升
- 2. let:不存在变量提升,存在暂时性死区
- 3. const:同 let,存在暂时性死区
- 三、重复声明规则
- 1. var:允许重复声明
- 2. let:不允许重复声明
- 3. const:不允许重复声明
- 四、赋值规则与常量特性
- 1. var:声明时可不赋值,可随意修改
- 2. let:声明时可不赋值,可修改值
- 3. const:声明时必须赋值,且不可重新赋值
前言
在 ES6(ECMAScript 2015)推出之前,JavaScript 声明变量只有var一种方式。ES6 新增了let和const两个关键字,彻底改变了前端变量声明的规范。三者在作用域、变量提升、重复声明、赋值规则等方面存在本质差异,也是前端面试的高频考点。本文将从底层机制出发,全面拆解三者的区别,所有结论均符合 ECMAScript 官方标准。
一、作用域不同
作用域决定了变量在代码中的可访问范围,这是三者最核心的区别。
1. var:函数作用域
var声明的变量只受函数作用域限制,不存在块级作用域。在if、for、{}等代码块中声明的var变量,在块外部依然可以访问。
2. let:块级作用域
let声明的变量拥有块级作用域,仅在当前代码块({}包裹的区域)内有效,外部无法访问。
3. const:块级作用域
const与let作用域规则完全一致,均为块级作用域,仅在声明的代码块内有效。
二、变量提升与暂时性死区
1. var:存在变量提升
var声明的变量会被提升到当前作用域的顶部,赋值操作留在原地。在声明之前访问变量,会得到undefined而非报错。
2. let:不存在变量提升,存在暂时性死区
let声明的变量不会被提升,在声明语句之前访问该变量,会直接抛出ReferenceError。从代码块开始到变量声明语句之间的区域,称为暂时性死区。
3. const:同 let,存在暂时性死区
const与let规则一致,声明前访问同样会报错。
三、重复声明规则
1. var:允许重复声明
同一作用域内,var可以多次声明同一个变量,后声明的会覆盖前者,不会报错。
2. let:不允许重复声明
同一作用域内,let不能重复声明同一个变量,否则直接报错。
3. const:不允许重复声明
与let一致,同一作用域内不可重复声明。
四、赋值规则与常量特性
1. var:声明时可不赋值,可随意修改
var声明时可以不赋值,默认值为undefined,后续可任意修改值和类型。
2. let:声明时可不赋值,可修改值
let声明时可以不赋值,后续可重新赋值,也可修改数据类型。
3. const:声明时必须赋值,且不可重新赋值
const代表常量,声明时必须立即初始化,不能留到以后赋值。且声明后,基本数据类型的值不可修改,引用数据类型的内存地址不可修改。
五、总结与最佳实践
通过前文对比,我们可以将var、let和const的核心差异总结如下:
| 特性 | var | let | const |
|---|---|---|---|
| 作用域 | 函数作用域 | 块级作用域 | 块级作用域 |
| 变量提升 | 存在(提升为undefined) | 不存在(存在暂时性死区) | 不存在(存在暂时性死区) |
| 重复声明 | 允许 | 不允许 | 不允许 |
| 初始赋值 | 可不赋值(默认undefined) | 可不赋值(默认undefined) | 必须赋值 |
| 重新赋值 | 允许 | 允许 | 不允许(基本类型值不可变,引用类型地址不可变) |
在不同开发场景下的选用建议:
- 循环场景(如 for、while)
- 优先使用
let:循环计数器、临时迭代变量等需要块级作用域隔离,避免变量泄露到外部。 - 避免使用
var:var会导致循环变量泄露,可能引发意外覆盖。 const仅用于循环内不会重新赋值的常量(如迭代配置对象)。
- 优先使用
- 常量定义
- 必须使用
const:用于声明不会重新赋值的常量,如配置项、枚举值、数学常数等。 - 确保初始化时赋值,且后续不修改其值(对于对象/数组,可修改内部属性,但不能重新赋值整个变量)。
- 必须使用
- 模块化开发(ES6 Module)
- 导出接口、工具函数、类定义等,优先使用
const保证引用稳定。 - 模块内部私有变量、状态管理,根据是否需要重新赋值选择
let或const。 - 现代前端框架(React、Vue)中,组件状态、响应式数据通常使用
const声明(配合框架的响应式系统更新值)。
- 导出接口、工具函数、类定义等,优先使用
- 函数内部变量
- 默认使用
const,只有当变量需要重新赋值时才改用let。 - 基本淘汰
var,除非维护遗留代码或特定需要函数作用域的场景。
- 默认使用
- 全局变量与顶层声明
- 在全局作用域或模块顶层,优先使用
const声明常量,使用let声明可修改变量。 - 避免使用
var污染全局对象(浏览器中var声明的全局变量会成为window属性)。
- 在全局作用域或模块顶层,优先使用
通用最佳实践:
- 默认使用
const,只有当变量需要重新赋值时才改用let。 - 基本不用
var,除非在 ES5 环境或特定需要函数作用域/变量提升的场景。 - 声明变量时尽量初始化,避免出现
undefined的中间状态。 - 利用块级作用域和暂时性死区减少变量污染和提升相关 bug。
- 使用 ESLint 等工具配置规则(如
no-var、prefer-const)强制代码规范。