浅谈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 规定constlet 命令都不会发生变量提升

  • 暂时性死区

如果一个代码块中使用了constlet 命令,那么它所声明的变量就会被绑定在这个区域,不再受外部的影响

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError
  let tmp;
}

上面的代码中,存在全局变量tmp ,但是在块级作用域let 又声明了一个局部变量tmp ,导致后者绑定了在这个作用域,所以在let 声明之前,对tmp 赋值就会报错

ES6 中规定,如果代码块内,存在letconst,那么这个代码块内声明的变量,从一开始就会形参封闭区域。凡是在声明之前就使用这些变量,就会报错,在语法上,称为"暂时性死区" (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 规定letconst 命令都不允许重复声明同一个变量

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 只是用来控制循环的,但是循环结束后,它并没有消失,泄露成了全局变量

发布于 2020-03-13 21:09