ES6 拾遗系列 一

779 阅读1分钟

ES6 拾遗系列 一 :let 和 const , 解构赋值 , 展开运算符

ES6 拾遗系列 二 : 箭头函数 , 模板字符串

let 和 const

问什么要引入 let 和 const ?

解决 var 声明变量带来的问题。

在 ES6 之前,声明变量只能通过 var ,使用var声明变量存在以下问题:

允许重复的变量声明:导致数据被覆盖

变量提升:怪异的数据访问、闭包问题

全局变量挂载到全局对象:全局对象成员污染问题

// 变量提升:怪异的数据访问
if (Math.random() < 0.5) {
    var a = "abc";
    console.log(a);
}
else {
    console.log(a);
}
console.log(a);//<0.5 abc   >=0.5 undefined

// 变量提升:闭包问题
var div = document.getElementById("divButtons")

for (var i = 1; i <= 10; i++) {
    var btn = document.createElement("button");
    btn.innerHTML = "按钮" + i;
    div.appendChild(btn);
    btn.onclick = function () {
        console.log(i); //输出11
    }
}
// 全局变量挂载到全局对象:全局对象成员污染问题
var abc = "123";
console.log(window.abc);

为了解决上述问题,ES6 新增了 let 和 const

let 和 const 的特性 ?

块级作用域:代码执行时遇到花括号,会创建一个块级作用域,花括号结束,销毁块级作用域

变量赋值:在同一个作用域内,let 声明的变量能重新赋值,const 在声明变量的同时必须赋值 ,且值不可修改,在作用域外无法访问声明的变量

变量提升:let 和 const 均不会有变量提升,因此,不能在使用 let 和 const 声明变量之前使用它。底层实现上,let 声明的变量实际上也会有提升,但是,提升后会将其放入到“暂时性死区”,如果访问的变量位于暂时性死区,则会报错:“Cannot access 'a' before initialization”。当代码运行到该变量的声明语句时,会将其从暂时性死区中移除。

闭包问题处理:在循环中,用 let 声明的循环变量,会特殊处理,每次进入循环体,都会开启一个新的块级作用域,并且将循环变量绑定到该作用域(每次循环,使用的是一个全新的循环变量)。循环中使用let声明的循环变量,在循环结束后会销毁。

mdn文档链接:let const

解构赋值

什么是解构赋值,它能做什么

解构赋值是 ES6 提供的一种语法糖,通过解构赋值,可以将属性/值从对象/数组中取出,并赋值给其他变量。

// 取得对象的值
const obj = {a:1, b:2};
let a = obj.a;
let b = obj.b;
console.log(obj.a,obj.b);
//取得数组的值
const arr =[1,2];
let num1 = arr[0];
let num2 = arr[1];

以下的代码和上面的代码结果一致,区别是下面的用了解构赋值

// 取得对象的值
const {a,b}={a:1,b:2};
//取得数组的值
const [num1,num2]=[1,2];

解构赋值在对象和数组解构赋值的时候会有差别,对象是按照属性取值,数组是按照index的顺序取值

另外对于解构赋值还提供了默认参数和变量重命名的语法糖

//默认参数
let {a,b=5,c=1}={a:1,b:2};
let [num1,num2=10,num3=1]=[1,2];
//变量重名名
let {a:a1,b}={a:1,b:2};
console.log(a1)//1
console.log(a)//报错 Uncaught ReferenceError: a is not defined

通过解构赋值,快速实现两变量值交换

let a=11,b=22;
[b,a]=[a,b];

解构赋值的原理(实现方式)

其内在是针对可迭代对象的Iterator接口,通过遍历器(for of)按顺序获取对应的值进行赋值

mdn文档链接:解构赋值

展开运算符

怎么使用展开运算符偷懒

展开运算符可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开

//字符串展开
let str='bar';
const strArr = [...str]; // ["b", "a", "r"]


//数组展开
const arr1 = [1,2,3];
const arr2 = [...arr1,4]; // [1,2,3,4]

//对象展开
const obj1 = {a:1,b:2};
const obj2 = {...obj1,c:3}; // {a: 1, b: 2, c: 3}


偷懒操作:使用展开运算符,代替部分api功能,减少 api 的记忆

//替换arr.concat()
const arr3 = [...arr1,...arr2]; //等价 const arr3 = arr1.concat(arr2);

//替换arr.push()
const arr3 = [1,2,3,4];arr3.push(...arr);//等价 arr3 = [1,2,3,4,...arr]

//替换arr.unshift()
const arr3 = [1,2,3,4];arr3.unshift(...arr)//等价 arr3 = [...arr,1,2,3,4]

//替换 Object.assign() 相同
const obj3 = {...obj1,...obj2} //等价 const obj3 = Object.assign({},obj1,obj2)

展开运算符除了能对字符串,数组,对象展开外,还能将剩余参数重新收集为数组和对象

//函数调用时使用(剩余参数)
let a1=1,a2=2,a3=3;
function sum(a1,...arr){
    console.log(arr)// [2,3]
    return a1*2 + arr.reduce((a,b)=>a+b) 
}
sum(a1,a2,a3) // 7

// 数组收集
[1, ...arr] = [1, 2, 3, 4]  // arr=[2,3,4]
//对象收集
{ a : 1 , ...obj } = {a:1, b:2} //obj={b:2}

mdn 文档:展开运算符 剩余参数