# ES6 解构赋值

> 解构赋值允许你使用类似数组或对象字面量的语法将数组和对象的属性赋给各种变量。

* 解构赋值的含义就好比其名，解开数据解构来进行赋值。个人认为解构赋值的目标在于减少代码的复杂程度，这也是js代码风格的一种体现。而其核心部分在于赋值时数据类型的一致。
* 解构赋值的语法极为清晰。区别于ES5通过属性访问数组或是对象的方法，善于使用解构赋值能够让代码变的更加简洁与美观。

## 数组解构

### 模式匹配

* 变量进行赋值时，只要等号两边的数据结构保持一致，即“模式匹配”，参数就能够赋值给变量。

  ```javascript
  // 最基础的一种赋值方法
  let [a, b, c] = [1, 2, 3];
  a // 1
  b // 2
  c // 3

  // 加一层后赋值
  let [a, [b], c] = [1, [2], 3];
  // 结果同上
  ```

  * 注：这里所说的数据结构保持一致是一种较为笼统的说法，对于数组赋值而言，其实只要等号右边的值具备Iterator接口就可以进行赋值，除数组外，还有Set类型等。
* 在生产过程中，不见得数组的每一个值都是我们所需要的，所以可以进行一定的省略。如果对应位置没有值，则赋值失败。

  ```javascript
  let [a, , b] = [1, 2, ]
  a // 1
  b // undefined
  ```
* 当然，我们也可能需要取数组中的一部分内容，取出得到的值依旧能够组成一个数组，这就需要用到解构赋值中的扩展运算符(...)。
* 扩展运算符能够对其后跟随的对象或数组进行一层拆解，如:

  ```
  ...[1, 2, 3] <=> 1, 2, 3
  ```

  这一串数字没有匹配的数据结构，直接输出这个语法会有报错。如果我们把它装进一个数组里，那自然也就对了

  ```javascript
  [...[1, 2, 3]] // [1, 2, 3]
  ```
* 回到之前说的赋值需要数组的其中一部分，那也就好处理了。需要注意的是扩展运算符用于数组赋值时，只能放于最后一位，放于中间或是开头都会匹配失败。

  ```javascript
  let [a, ...b] = [1, 2, 3]
  a // 1
  b // [2, 3]

  let [...c, d] = [1, 2, 3] // error
  let [e, ...f, g] = [1, 2, 3] // error
  ```

### 默认值

* 解构赋值也能够如同函数入参一样赋有一个默认值，当赋值时，参数对应的值等于undefined时(严格等于)，赋值结果就会采用该默认值。

```javascript
let [a = 1, b = 1, c = 1] = [undefined, null, 3]
a // 1
b // null => null与undefined不为严格相等
c // 3
```

* 默认值也可以取为一个表达式，这个表达式具有惰性，即只有默认值被取到时，才会执行表达式。反之则不执行。

```javascript
function f() {
  console.log('111');
}
let [a = f()] = [undefined]
// '111'
```

### 常见用法

* 解构赋值可以就业的场景很多，这边列举一个比较常用的函数入参赋值的场景。

  ```javascript
  function f(a, b, c) {
    console.log(a, b, c);
  }
  let args = [1, 2, 3];
  f(...args);
  // 1 2 3
  ```

## 对象解构

* 在js中，我们可以将数组理解为一种具有顺序的对象，所以赋值根据次序来进行即可。而对于一般对象来说，不具备次序特征，所以对象赋值的原则就需要变量与属性同名，才能够正确进行。

  ```javascript
  let { a, b } = { a: 1, b: 2 }
  a // 1
  b // 2

  let { c } = { d: 1 } // error
  ```
* 对对象的解构能够方便的将现有对象的方法赋值到某一个变量上来实现代码的简化

  ```javascript
  let { log } = console
  log('111');
  // '111'
  ```
* 其实解构赋值对于不同名的参数而言也是支持的，但是同数据解构是必要的。

  ```javascript
  let { a: c, b: d} = { a: 1, b: 2}
  c // 1
  d // 2 

  //参数同名可以理解为下面这个例子的一种省略
  let { a: a, b: b } = { a: 1, b: 2 }
  ```

  * 所以对象的赋值机制其实是先找到同名属性，并对属性对应的变量进行赋值。真正被复制的是后者，而不是前者。前者是模式，后者才是变量。

### 模式匹配

* 对象的模式匹配与数组同理，不外乎数据结构相同，不同于数组的就在于需要变量名称对应。需要注意的是参数所匹配的是模式还是变量。

  ```javascript
  let obj = {
    a: [ 1, { c: 2 } ]
  };
  let { a: [ b, { c } ] } = obj;

  a // not defined
  b // 1
  c // 2
  ```

  * 如果对于模式与变量的概念了解清楚了，那就很好理解这个例子。a作为对象属性，因为其是一种模式所以无法解构。b对应于数组中的第一个位置，所以能够解构。c与对象中的属性c同名，所以能够解构。
  * 总而言之就是两个关键词：同名、同结构。

### 默认值

* 与数组用法类似，需要满足undefined严格相等，以及对象解构同名的原则。这里不再赘述。

### 常见用法

* 当一个对象作为一个入参而使用时，我们往往只需要使用对象中部分属性的值，这个时候就可以使用解构赋值。

  ```javascript
  function f({ a, b }) {
    console.log(a, b);
  }
  let obj = { a: 1, b: 2, c: 3 }
  f(obj)
  // 1 2
  ```

## 其他解构
