ES6到ES10— let、const

140 阅读5分钟

1.回顾var

基本用法

早在ES6前我们定义变量使用var命令
使用方式如下:

var a = 10;

有些问题

在使用var来定义变量时,根据js的语言机制,我们会遇见一些问题,最最常见的就是以下几种

  1. 变量提升
console.log(a);//undefined 变量a进行了提升
var a = 1;
  1. 没有块级作用域
    经典案例来袭 haha
var a = [];
for(var i = 0; i<10; i++){
    a[i] = function(){
        console.log(i)
    }
}
a[6]();//10
console.log(i); //10 变量泄漏到全局
  1. 重复声明
    var a = 1 ;
    //...
    //在代码量很大时,开发者会无意间重复声明覆盖变量
    var a = 2 ;

ES6的解决

为了解决var没有块级作用域、变量泄漏到全局、变量提升、变量可以重复声明等问题,ES6出现了let、const两种新的命令,下面介绍这两种命令的各自特点

2.let 命令

基本用法

ES6新增命令,用来声明变量,和var的使用方式类似,但是声明的变量只在let所在的代码块内有效

{
    let a = 10;
    var b = 1;
}
console.log(a)// a is not defined  超出let定义的代码块范围
console.log(b)//1

for循环中的使用

因为let只在定义块级中有效,因为let特别适用在for循环中

for(let i = 0; i<10; i++){
    //...
}
console.log(i);// i is not defined

上述的经典案例为了解决数组内每个函数都打印10的问题,通常会使用立即执行函数进行处理,但是使用let就方便很多了,我们来看一下

var a = [];
for(let i = 0; i<10; i++){
    a[i] = function(){
        console.log(i);
    }
}
a[6]();//6
console.log(i) //i is not defined 这里就不存在变量泄漏全局的问题了

上述代码有两处需要注意

  1. 因为let定义的i只在每次循环的块级作用域中生效,也就是每次循环都会新生成一个i,每个i都是一个新的变量
  2. for循环中每次在生成i的时候,JS引擎会记住上轮循环的值,初始化本轮的i时会根据上一轮的i值进行计算
  3. 循环结束后在外围调用i会报错,因为i只在循环时的块级作用中生效,这也就解决了变量泄漏的问题

无变量提升

字面意思let定义的变量不存在变量提升

console.log(a); a is not defined 报错!无法在声明变量之前使用
let a = 1;

暂时性死区

暂时性死区:temporal dead zone,简称 TDZ
通俗的解释是在代码块内let、const命令声明变量之前,该变量都是无法使用的

    var a = 123;
    if(true){
    // ReferenceError 报错,如果块级内let、const定义了该变量,那么在该变量声明之前无法使用,在声明前这个无法使用该变量的区域就叫做暂时性死区
        a = 321;
        let a;
    }

不能重复声明

同字面意思,let和const定义的变量在同块级作用域内无法重复声明

//报错
function(){
    let a = 1;
    var a = 10;
}
//报错
function(){
    let a = 1;
    let a = 10;
}

3.块级作用域

为什么需要块级作用域

举两个最简单的例子

  1. 内层变量覆盖外层变量
var a = 1;
function fn(){
    console.log(a);//2.这里打印的就是被提升的a,从而出现了内层变量覆盖了外层
    if(false){
    	//1.没有块级作用域,此时if中的a会被提升到函数内部最上层
    	var a = 2;
    }
}
fn(); //undefined
  1. 变量泄漏为全局变量

这点之前的案例中已经有提到,var定义的变量 for循环结束后,变量会泄漏到全局不会消失

let、const带来了块级作用域

ES6之前并没有块级作用域,实际上let、const为JS带来了块级作用域,使得JS在{}代码块内具有作用域,我们之前展示的案例,体现了这一点
但是有几点需要注意:

  1. ES6之前块级作用域内不予许声明函数ES6后可以
  2. 函数声明会提升到全局作用域或函数作用域的头部
  3. 函数声明会提升到所在块级作用域的头部
  4. ES6中的块级作用域必须要有大括号
if(true) let a = 1;//报错
if(true){
    let a = 1;//可以
}

4.const 命令

基本用法

const 声明一个只读的常量,一但声明常量的值就不能改变

const a = 1
a = 2//报错
const b; //报错 由于b声明的变量不可以改变值,那么const声明的变量在声明时就必须要初始化值

const的本质

实际上const保证的并不是变量的值不发生改变,而是变量指向的内存地址保存的数据不能改变,简单数据类型(数字、字符串、布尔值),值就保存在变量指向的那个内存地址,相当于常量,但是复杂数据类型保存的是一个指向实际数据的指针,因此只要保证指针不发生变化就可以;

    const obj = {};
    obj.name = "jack"; //可以
    obj = {}//报错!地址改变
    const arr = [];
    arr.push(1);//可以
    arr = []//报错!地址改变

基于const的特性,建议开发时除非明确的知道变量需要发生改变,否则建议使用const声明变量

和let特性相同

const 和 let 相同都有块级作用域、不能重复定义、没有变量提升、暂时性死区等特性