ES6+知识点汇总(2)— 彻底掌握解构赋值

132 阅读7分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情

六、解构赋值

解构赋值即:解析某一数据的结构,将我们想要的东西提取出来,赋值给变量或常量。

6-1、数组的解构赋值

6-1-1、数组解构赋值的原理

原理:首先进行结构匹配,结构匹配上了后将索引值相同的完成赋值。

const [a, b, c] = [1, 2, 3];
console.log(a,b,c); // 1 2 3

const [a,,c] = [1,[2,3,4,5],6];
console.log(a,c); // 1 6

const [a, [,,,b],c] = [1,[2,3,4,5],6];
console.log(a,b,c); // 1 5 6

可见,首先左右两边结构要对应的上,右边为数组,左边也要为数组解构;然后再与想取的内容的索引对应的上:不想取的内容用逗号隔开即可。

6-1-2、数组解构赋值的默认值

我们先来看以下代码:

const [a,b] = [];
console.log(a, b); // undefined undefined

以上代码相当于:const [a, b] = [undefined, undefined];

如果我们想要在不存在值的时候给默认值如何做呢?

我们可以这样:

const [a = 1,b = 2] = [];
console.log(a, b);// 1 2

我们要注意默认值的生效条件为:只有当一个数组成员严格等于(===)undefined时,对应的默认值才会生效:

const [a = 1,b = 2] = [3, 4];
console.log(a, b); // 3 4 由于对应索引存在值,所以默认值不生效

const [a = 1, b = 2] = [3, null]; // 3 null , null 并不严格等于undefined

const [a = 1, b = 2] = [3]; // 3 2 ,此时b对应的索引值的内容为undefined所以b的默认值生效了

如果默认值时表达式,那么默认值的表达式是惰性求值的:

const fun = () => {
  console.log('执行了...');
  return 2;
}
const [x = fun()] = [1];
console.log(x); // 1

可见,控制台只输出了1,而没有输出执行了...这句话,这是因为fun没有被真正执行,x对应的索引存在1了,所以不会执行fun,fun的执行是惰性的(用不着默认值,表达式并不会执行;用到的话才会去执行)

6-1-3、数组解构赋值的应用

6-1-3-1、类数组的解构赋值
function a() {
  const [a, b] = arguments;
  console.log(a, b); // 1 2
}
a(1, 2);
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>数组解构赋值的应用</title>
  </head>
  <body>
    <p>123</p>
    <p>321</p>
    <p>34567</p>
    <script>
      // NodeList
      const [p1, p2, p3] = document.querySelectorAll('p');
      console.log(p1, p2, p3);
    </script>
  </body>
</html>
6-1-3-2、函数参数的解构赋值
const array = [1, 1];
// const add = arr => arr[0] + arr[1];
// 我们可采用解构赋值的方式计算:
const add = ([x = 0, y = 0]) => x + y;
console.log(add(array));
console.log(add([]));
6-1-3-3、交换变量
      let x = 1;
      let y = 2;

      // let tmp = x;
      // x = y;
      // y = tmp;
      // console.log(x, y);

      [x, y] = [y, x];
      console.log(x, y);

6-2、对象的解构赋值

6-2-1、对象解构赋值原理

首先也是进行结构匹配,结构匹配上后,将属性名相同的完成赋值。

const { age, username } = { username: 'zhangsan', age: 18 };
// 完整写法:
const { age: age, username: username } = { username: 'zhangsan', age: 18 };
console.log(age, username); // 18 zhangsan

我们可以对解构的属性取别名:

const { age: age, username: name } = { username: 'zhangsan', age: 18 };
console.log(age, name);

6-2-2、对象解构赋值的默认值

对象解构赋值默认值的生效条件为:对象的属性值严格等于undefined时,对应的默认值才会生效。

const { username = 'zhangsan', age = 0 } = { username: 'lisi' };
console.log(username, age);// lisi 0

同样,与数组解构赋值默认值类似,对象解构赋值的默认值是表达式时也是惰性求值的。

6-2-3、对象解构赋值的注意事项

1、将一个已经声明的变量用于解构赋值的注意事项

let x = 1;
// let { x } = {x: 2}; //这里会报x已经声明的错误

// 那我们这样写呢:
// { x } = { x : 2}; // 注意这样也是不可以的,会被浏览器误认为是代码块的{}
// 所以我们此时要使用()包裹,让整个赋值在圆括号中进行:
({ x } = { x: 2});
  • 所以,将已经声明的变量进行对象的解构赋值时,赋值过程要在圆括号中进行(以免让浏览器误认为对象的{}时函数体)

2、对象的解构赋值是可以取到继承的属性的

const { toString } = {};
console.log(toString); // f toString() {}
// 由于toString在Object的prototype属性上,所以可以顺着原型链找到

6-2-4、对象解构赋值的应用

6-2-4-1、对函数参数的解构赋值
// const logPersonInfo = user => console.log(user.username, user.age);
const logPersonInfo = ({ age = 0, username = 'zhangsan' }) => console.log(username, age);
logPersonInfo({ username: 'lisi', age: 18 }); // lisi 18
logPersonInfo({}); // zhangsan 0
6-2-4-2、对复杂嵌套对象进行解构赋值
const obj = {
  x: 1,
  y: [2, 3, 4],
  z: {
    a: 5,
    b: 6
  }
};
const {
  y,
  y: [, yy],
  z,
  z: { b }
} = obj;
console.log(yy, y, z, b); // 3 [2,3,4] {a:5, b: 6} 6

第一个y使用来取obj中的整个y属性对应的内容的,yy是用来取y对应数组的第二个索引对应的内容“3”的,z是用来取z属性对应的整个对象的,而b是用来取z属性对应对象中b属性对应的内容的。

6-3、字符串的解构赋值

字符串的解构赋值比较特殊,其既可以用数组的形式进行解构赋值,也可以用对象的形式进行解构赋值(而不能用字符串的形式进行解构赋值):

6-3-1、使用数组的形式进行解构赋值

const [a, b, , , c] = 'hello';
console.log(a, b, c); //  h e o

6-3-2、使用对象的进行进行解构赋值

const { 0: a, 1: b, length } = 'hello';
console.log(a, b, length); // h e 5
console.log('hello'.length) // 5

按照对象的形式进行解构赋值时,属性值对应的是字符串的索引,想取第几个位置的字符,属性值就写几;除此之外还可以取出字符串的length属性(因为可以直接使用字符串上本身就有length属性)

6-4、数值与布尔值的解构赋值(扩展)

数值与布尔值进行解构赋值时不能使用数组的形式(因为它们没有length属性),只能使用对象的形式进行解构赋值,在使用对象形式对数值/布尔值进行解构赋值时,会尝试将数值/布尔值转换为对应的包装对象(Number Boolean)

const { a = 1, toString } = 123;
console.log(a, toString); // 1  f toString(){} 
// 123上没有属性a,所以会输出默认值1,Number包装类上存在属性toString,所以会输出toString方法

同样:也可以使用对象的形式对布尔值进行解构赋值

const { b = 2, toString } = true;
console.log(b, toString); // 2 f toString(){}

6-5、undefined与null的解构赋值(扩展)

由于undefined与null没有对应的包装对象,无法通过它们转换成相应的对象,所以对它们进行解构赋值,都会报错

6-6、解构赋值常见场景汇总

6-6-1、交换变量

let a = 1;
let b = 2;
[a, b] = [b, a]; // 注意a与b已经声明过了,这里就不要添加let了
console.log(a, b); // 2 1

6-6-2、从函数返回多个值

函数只能返回一个值,如果要返回多个值,只能将这些值放入一个数组或对象里。此时我们可以使用解构赋值,可以很方便的提取出这些值:

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();
console.log(a, b, c); // 1 2 3

function example2() {
  return {
    x: 1,
    y: 2
  };
}
let { x, y } = example2();
console.log(x, y); // 1 2

6-6-3、函数参数的定义

利用解构赋值也可以将一组参数与变量名对应起来:

function fun([x, y, z]) {
  console.log(x, y, z); // 1 2 3
}
fun([1,2,3]);

function fun2({a, b, c}) {
  console.log(a, b, c); // 2 3 1
}
fun2({c: 1, a: 2, b: 3});

6-6-4、指定函数参数的默认值

指定参数的默认值,就避免了在函数体内部再去判断传入的参数是否有值了

function foo({x, y = 5}) {
  console.log(x, y);
}
foo({x: 1}); // 1 5
foo({x: 1, y: 2}); // 1 2

6-6-5、遍历Map解构

利用解构赋值去获取map的键名和键值就会很方便:

var map = new Map();
map.set('zs', '18');
map.set('ls', '20');
for(let [key, value] of map) {
  console.log(`${key}今年${value}岁`);
}

6-6-6、加载模块

加载模块也利用了解构,可以让引入的部分更加明确

import {a, b} from 'xxx';

6-6-7、提取JSON数据

const jsonData = {
  "name": "zs",
  "age": "18",
  "number": "17111111111"
}
let {name, age, number} = jsonData;
console.log(name, age, number);