Alan

1、基本语法

1.1、数组

``````// 基础类型解构
let [a, b, c] = [1, 2, 3]
console.log(a, b, c) // 1, 2, 3

// 对象数组解构
let [a, b, c] = [{name: '1'}, {name: '2'}, {name: '3'}]
console.log(a, b, c) // {name: '1'}, {name: '2'}, {name: '3'}

// ...解构
let [head, ...tail] = [1, 2, 3, 4]
console.log(head, tail) // 1, [2, 3, 4]

// 嵌套解构
let [a, [b], d] = [1, [2, 3], 4]
console.log(a, b, d) // 1, 2, 4

// 解构不成功为undefined
let [a, b, c] = [1]
console.log(a, b, c) // 1, undefined, undefined

// 解构默认赋值
let [x = 1] = [undefined];// x=1;
let [x = 1] = [null];// x=null; // 数组成员严格等于undefined，默认值才会生效
let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2];    // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError: y is not defined 因为x用y做默认值时，y还没有声明``````

1.2 对象

``````// 对象属性解构
let { f1, f2 } = { f1: 'test1', f2: 'test2' }
console.log(f1, f2) // test1, test2

// 可以不按照顺序，这是数组解构和对象解构的区别之一
let { f2, f1 } = { f1: 'test1', f2: 'test2' }
console.log(f1, f2) // test1, test2

// 解构对象重命名
let { f1: rename, f2 } = { f1: 'test1', f2: 'test2' }
console.log(rename, f2) // test1, test2

// 嵌套解构
let { f1: {f11}} = { f1: { f11: 'test11', f12: 'test12' } }
console.log(f11) // test11

// 默认值
let { f1 = 'test1', f2: rename = 'test2' } = { f1: 'current1', f2: 'current2'}
console.log(f1, rename) // current1, current2``````

1.3 字符串/数值/布尔值

``````// String
let [ a, b, c, ...rest ] = 'test123'
console.log(a, b, c, rest) // t, e, s, [ 't', '1', '2', '3' ]
let {length : len} = 'hello'; // en // 5

// number
let {toString: s} = 123;
s === Number.prototype.toString // true

// boolean
let {toString: s} = true;
s === Boolean.prototype.toString // true

// Map
let [a, b] = new Map().set('f1', 'test1').set('f2', 'test2')
console.log(a, b) // [ 'f1', 'test1' ], [ 'f2', 'test2' ]

// Set
let [a, b] = new Set([1, 2, 3])
console.log(a, b) // 1, 2``````

2、使用场景

2.1、 浅拷贝

``````let colors = [ "red", "green", "blue" ];
let [ ...clonedColors ] = colors;
console.log(clonedColors);  // "[red,green,blue]"``````

2.2、 交换变量

``````let x = 1;
let y = 2;
[x, y] = [y, x];``````

2.3、遍历Map结构

``````var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
console.log(key + " is " + value);
}``````

2.4、函数参数

``````function add(a,b,{c,d}){
// ...
}
add(1,2)//Uncaught TypeError: Cannot destructure property `c` of 'undefined' or 'null'``````

``````function add(a, b, options) {
let { c,d } = options;
// ...
}``````

``````function add(a,b,{c,d}={}){
// ...
}``````

``````function move ({x:0,y:0}={}){}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]``````
``````function move ({x,y}={x:0,y:0}){}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]``````

`undefined`就会触发函数参数的默认值。

``[1, undefined, 3].map((x = 'yes') => x);``

3、基本原理

• Iterator
• 可迭代对象

3.1、Iterator概念

`Iterato`r是一种接口，为各种不一样的数据解构提供统一的访问机制。任何数据解构只要有`Iterator`接口，就能通过遍历操作，依次按顺序处理数据结构内所有成员。ES6中的for of的语法相当于遍历器，会在遍历数据结构时，自动寻找`Iterator`接口。
Iterator作用：

• 为各种数据解构提供统一的访问接口
• 使得数据解构能按次序排列处理
• 可以使用ES6最新命令 for of进行遍历
``````function makeIterator(array) {
var nextIndex = 0
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++]} :
{done: true}
}
};
}

var it = makeIterator([0, 1, 2])
console.log(it.next().value) // 0
console.log(it.next().value) // 1
console.log(it.next().value) // 2``````

3.2、可迭代对象

`可迭代协议`：对象必须实现`@@iterator`方法。即对象或其原型链上必须有一个名叫`Symbol.iterator`的属性。该属性的值为无参函数，函数返回迭代器协议。

`Symbol.iterator` 返回一个对象的无参函数，被返回对象符合迭代器协议。

`迭代器协议`：定义了标准的方式来产生一个有限或无限序列值。其要求必须实现一个`next()`方法，该方法返回对象有`done(boolean)``value`属性。

`next` 返回一个对象的无参函数，被返回对象拥有两个属性：`done``value`
`done` :如果迭代器已经经过了被迭代序列时为 true。这时 value 可能描述了该迭代器的返回值。如果迭代器可以产生序列中的下一个值，则为 false。这等效于连同 done 属性也不指定。
`value` :迭代器返回的任何 JavaScript 值。done 为 true 时可省略。

3.3、解构语法糖

`String``Array``Map``Set`等原生数据结构都是可迭代对象，可以通过`for of`循环遍历它。故可以通过ES6解构语法糖依次获取对应的值。

``````// String
let str = 'test'
let iterFun = str[Symbol.iterator]
let iterator = str[Symbol.iterator]()
let first = iterator.next() // 等效于 let [first] = 'test'
console.log(iterFun, iterator, first)
// 打印
// [Function: [Symbol.iterator]], {}, { value: 't', done: false }

// Array
let arr = ['a', 'b', 'c'];
let iter = arr[Symbol.iterator]();

// 以下等效于 let [first, second, third, four] = ['a', 'b', 'c']
let first = iter.next() // { value: 'a', done: false }
let second = iter.next() // { value: 'b', done: false }
let third = iter.next() // { value: 'c', done: false }
let four = iter.next() // { value: undefined, done: true }
``````

4、性能

参考

ES6 的解构赋值前每次都创建一个对象吗？会加重 GC 的负担吗？

1.5k 声望
1.7k 粉丝