浅谈var、let 和 const 的区别
ES6 中新增let
命令,用来声明变量。它的用法类似于var,但是不存在变量提升,且只在let
命令所在的代码块内有效,
const
是用了声明只读常量的,一旦声明,常量的值就不能修改
下图表明了它们的区别
下面我们就来证明一下吧
- 变量提升
变量提升,即变量可以在声明之前使用,值为undefined
console.log(a) // 正常运行,打印出 undefined
var a = 1
------------------------
console.log(b) // 报错,Uncaught ReferenceError: b is not defined
let b = 1
------------------------
console.log(c) // 报错,Uncaught ReferenceError: b is not defined
const c = 1
可以看出只有var
存在变量提升的问题,按照一般的逻辑,变量应该在声明之后再使用才对,所以ES6 规定const
和 let
命令都不会发生变量提升 。
- 暂时性死区
如果一个代码块中使用了const
或 let
命令,那么它所声明的变量就会被绑定在这个区域,不再受外部的影响
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
上面的代码中,存在全局变量tmp
,但是在块级作用域let
又声明了一个局部变量tmp
,导致后者绑定了在这个作用域,所以在let
声明之前,对tmp
赋值就会报错
ES6 中规定,如果代码块内,存在let
或 const
,那么这个代码块内声明的变量,从一开始就会形参封闭区域。凡是在声明之前就使用这些变量,就会报错,在语法上,称为"暂时性死区" (temporal dead zone)
- 重复声明
指在相同的作用域内,重复声明同一个变量
function func(){
let a = 10;
const PI = 3.1415;
var a = 1;// 报错,Uncaught SyntaxError: Identifier 'a' has already been declared
var PI = 3;// 报错,Uncaught SyntaxError: Identifier 'PI' has already been declared
}
// 当调用func()时报错,Uncaught SyntaxError: Identifier 'a' has already been declared
function func(){
let a = 10;
const PI = 3.1415;
let a = 1;// 报错,Uncaught SyntaxError: Identifier 'a' has already been declared
const PI = 3;// 报错,Uncaught SyntaxError: Identifier 'PI' has already been declared
}
ES6 规定let
和const
命令都不允许重复声明同一个变量
而var
是允许重复声明的,但重复声明显然是不建议的
- 初始值
const
声明的是一个只读的常量,一旦声明,就必须赋初始值,而且声明之后不允许改变
const PI = 3.1415
PI = 3 // 报错,Uncaught TypeError: Assignment to constant variable.
- 作用域
在ES5 中只用全局作用域和函数作用域,没有块级作用域,这会带来很多不合理的场景
一、内层变量可能会覆盖外层变量
var tmp = new Date();//处于全局作用域
function fn() {
console.log(tmp);//处于函数作用域
if (false) {
var tmp = 'hello world';
}
}
fn(); // undefined
代码的原意是,if
代码块的外部使用外层的tmp
,内部使用内部的tmp
变量
但是实际是这样的,function 的两个tmp
处在同一作用域,由于变量提升,导致函数作用域中的tmp
覆盖全局变量中的 tmp
,所以,fn() 输出的结果为undefined
二、用来计数的循环变量,泄露覆盖全局变量
var i = 10;
for(var i = 0;i < 5;i++){
console.log(i);
}
console.log(i);// 输出 5
上面的代码中,变量i
只是用来控制循环的,但是循环结束后,它并没有消失,泄露成了全局变量