关于var、let 和const

166 阅读3分钟

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声明的变量是不能修改引用空间。