简介
在ECMAScript6中新增两个变量声明的指令let
和const
,以前经常用的var
有什么区别。
var 声明
var
声明语句声明一个变量,并可选地将其初始化为一个值。
- 可重复声明
- 变量提升
- 声明变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的。
1 | var count = 1; |
通过var
关键字声明一个count
变量,并且count
的值为 1。
可重复声明
可以重复声明count
变量,也可以重新赋值,代码如下:
1 | var count = 1; |
变量提升
var
声明的变量是存在变量提升的 ,由于变量声明(以及其他声明)总是在任意代码执行之前处理的,所以在代码中的任意位置声明变量总是等效于在代码开头声明。代码如下:
1 | console.log(count); // undefined |
提升将影响变量声明,而不会影响其值的初始化。
作用域
var
声明变量的作用域限制在其声明位置的上下文中,而非声明变量总是全局的。代码如下:
1 | function x() { |
- 建议始终声明变量,无论它们是在函数还是全局作用域内。
let 声明
let
允许你声明一个作用域被限制在 块级中的变量
、语句或者表达式
。与 var
关键字不同的是, var
声明的变量只能是全局
或者整个函数块
的。
- 不可重复声明,可以重复赋值
- 块作用域
- 暂存死区
- 不存在变量提升
不可重复声明,可以重复赋值
let
不可以重复同样名称的变量,但是可以重复给同一个变量多次赋值。代码如下:
1 | let count = 1; |
块作用域
let
声明的变量只在其声明的块或子块中可用,这一点,与var
相似。二者之间最主要的区别在于var
声明的变量的作用域是整个封闭函数。
1 | function varTest() { |
let 声明的变量不会挂载顶层对象下面,会临时创建一个scope
来储存let 声明,执行完成清除,示例代码如下:
1 | <script> |
在执行完let count = 1;
,效果如下图所示:
当javascript执行完成后,scope
也会被清空。
暂存死区/不存在变量提升
let
被创建在包含该声明的(块)作用域顶部,一般被称为“提升”。与通过 var
声明的有初始化值 undefined
的变量不同,通过 let
声明的变量直到它们的定义被执行时才初始化。在变量初始化前访问该变量会导致 ReferenceError
。该变量处在一个自块顶部到初始化处理的“暂存死区”中。
代码如下:
1 | console.log(count); // Uncaught ReferenceError: Cannot access 'count' before initialization |
const 声明
常量是块级作用域,很像使用 let
语句定义的变量。常量的值不能通过重新赋值来改变,并且不能重新声明。
- 不能重复声明
- 不能重复赋值
- 块级作用域
- 暂存死区
- 不存在变量提升
- 一旦声明,必须马上赋值
不能重复声明
、块级作用域
、块级作用域
、不存在变量提升
在这里不再赘述和let
中的表现相同,请看上文。
一旦声明,必须马上赋值
const
声明之后必须马上赋值,否则会报错,代码如下:
1 | const count; // Uncaught SyntaxError: Missing initializer in const declaration |
不能重复赋值
const
声明创建一个值的只读引用。但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。
JavaScript中的数据类型分为两大类:值类型
、引用类型
。
值类型
用const
声明的变量被首次被赋值为值类型,它的值就不能改变了,代码如下:
1 | const count = 1; |
引用类型
只要不改变量的指针地址就不会报错,代码如下:
1 | const user = { |
总结
总结对比如下面表格所示:
/ | 能否重复声明 | 能否重复赋值 | 作用域 | 变量提升 | 暂存死区 | 声明是否需要立即赋值 |
---|---|---|---|---|---|---|
var | 能 | 能 | 函数作用域/全局作用域 | 存在变量提升 | 不存在暂存死区 | 不需要立即赋值 |
let | 不能 | 能 | 块级作用域/全局作用域 | 不存在 | 存在暂存死区 | 不需要立即赋值 |
const | 不能 | 不能 | 块级作用域/全局作用域 | 不存在 | 存在暂存死区 | 需要立即赋值 |
他们的特性基本上如上面表格所示,可以根据各个不同的需要,选择 var、let、const 来声明变量。