let和const的诞生:
在es6出现之前作用域分为函数作用域和全局作用域,es6为我们提供了新的声明方式let和const替代了之前的var
var的痛点:
1. var不支持封闭作用域,会声明到全局作用域上,如下所示声明的变量 i,会直接挂载到window上,这样会带来很多问题。
for(var i=0;i<3;i++){
console.log(i); // 0,1,2
}
console.log(i); // 3
console.log(window.i); // 3
那么如何让变量不挂载到全局上,在es6出现之前可以利用闭包,此时在函数外会访问不到i,console就会报错。
(function(){
for(var i=0;i<3;i++){
console.log(i); // 0,1,2
}})();console.log(i); //报错
当异步代码遇到变量时
for(var i=0;i<3;i++){
setTimeout(function(){
console.log(i); //3, 3, 3
}, 1000);}
但是此时我想让它照常输出0,1,2,怎么办呢?依然可以利用闭包,
for(var i=0;i<3;i++){
(function(i){
setTimeout(function(){
console.log(i); // 0,1,2
}, 1000);
})(i)}
如上所示,就可以正常输出0,1,2,但这样的代码看上去很不美观,此时有一个更优的方法解决这个问题,就是用es6的let:
for(let i=0;i<3;i++){
setTimeout(function(){
console.log(i); // 0, 1, 2
}, 1000);}
console.log(i); // 会报错
如上所示,成功的解决了问题。由此可见当let和{ }配合可以产生一个作用域,这就是块级作用域,let支持块级作用域,声明的变量只会在当前作用域内,所以使用let可以解决作用域污染问题和局部作用域问题。
2. 在同一个作用域下可以多次声明同一个变量
如下所示,后声明的a会覆盖之前的a,所以此时输出的是2
var a=0;
function b(){
var a=1;
var a=2;
console.log(a); // 2
}
如果此处换成let,就不会允许a被重复声明
var a=0;
function b(){
let a=1;
let a=2;
console.log(a); //会报错
}
如果用let声明过了,就不要再用var了,此时也会报错
var a=0;
function b(){
let a=1;
var a=2;
console.log(a); //也会报错
}
并且let不支持预解析,变量提升
在es5中,有变量提升,所以此处的console是undefined,
console.log(a); // undefined
var a=1;
但是在es6中,不支持变量提升,此处的console会报错,必须是先声明,再使用,这样更符合代码规范。
console.log(a); // 报错
let a=1;
let有暂存死区:
let a=1;{ let a =2; console.log(a); // 2}
let a=1;{ console.log(a); // 会报错 let a =2;}
let a=1;{ console.log(a); // 1}
如果作用域内有这个变量,那么在这个作用域内就会绑定这个变量,不会向上查找,如果没有这个变量则会向上查找,这就是暂存死区。
关于const:
const和let基本一致,但是通过const声明的变量不可被修改,通过let声明的变量可修改,如下:
const a=1;
const a=2;
此时就会报错。但是如果我们这样修改变量是可以的:
const a = {name:"tom"};
a.age = 9;
const声明的变量是不能修改引用空间。