var、let 和 const 都是 JavaScript 中用来声明变量的关键字,并且 let 和 const 关键字是在 ES6 中才新增的。
1、var 与 let 的区别
(1)作用域
var 声明的变量的作用域只能是全局或者整个函数块的。
let 声明的变量的作用域则是它当前所处代码块,即它的作用域既可以是全局或者整个函数块,也可以是 if、while、switch等用{}
限定的代码块。
另外,var 和 let 的作用域规则都是一样的,其声明的变量只在其声明的块或子块中可用。
function varTest() {
var a = 1;
{
var a = 2; // 函数块中,同一个变量
console.log(a); // 2
}
console.log(a); // 2
}
function letTest() {
let a = 1;
{
let a = 2; // 代码块中,新的变量
console.log(a); // 2
}
console.log(a); // 1
}
varTest();
letTest();
let 声明的变量的作用域可以比 var 声明的变量的作用域有更小的限定范围,更具灵活。
(2)重复声明
var 允许在同一作用域中重复声明,而 let 不允许在同一作用域中重复声明,否则将抛出异常。
var a = 1;
var a = 2;
console.log(a) // 2
let a = 1;
let a = 2; // SyntaxError: Identifier 'a' has already been declared
switch(index) {
case 0:
let a = 1;
break;
default:
let a = 2; // SyntaxError: Identifier 'a' has already been declared
break;
}
let 声明的重复性检查是在代码正式开始执行之前就会进行检查。
(3)绑定全局对象
var 在全局环境声明变量,会在全局对象里新建一个属性,而 let 在全局环境声明变量,则不会在全局对象里新建一个属性。
var foo = 'global'
let bar = 'global'
console.log(this.foo) // global
console.log(this.bar) // undefined
let 在全局环境声明变量 bar 保存在[[Scopes]][0]: Script
这个变量对象的属性中,而[[Scopes]][1]: Global
就是我们常说的全局对象。
(4)变量提升与暂存死区
4.1 var的变量提升
console.log(a) // undefined
var a = 1;
console.log(a) // 1
//////////////////////////相当于以下代码
var a;//先声明变量
console.log(a);
a = 1;//再给变量赋值
console.log(a);
4.2 let的暂存死区
let 在变量初始化前访问该变量会导致 ReferenceError
,因此从进入作用域创建变量, 到变量开始可被访问的一段时间(过程),就称为暂存死区(Temporal Dead Zone)。
console.log(bar); // undefined
console.log(foo); // ReferenceError: foo is not defined
var bar = 1;
let foo = 2;
var foo = 33;
{
let foo = (foo + 55); // ReferenceError: foo is not defined
}
总结:var再创建变量时会将变量初始化为undefined,而let不会被初始化。
3.let 与 const 异同
const 与 let 很类似,都具有上面提到的 let 的特性,唯一区别就在于 const 声明的是一个只读变量,声明之后不允许改变其值。因此,const 一旦声明必须初始化,否则会报错。
let a;
const b = "constant";
a = "variable";
b = 'change'; // TypeError: Assignment to constant variable
其实 const 其实保证的不是变量的值不变,而是保证变量指向的内存地址所保存的数据不允许改动(即栈内存在的值和地址)。