ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
数组的解构赋值
基本用法
左右两边模式相同,即可赋值:
1 2 3 4 5
| let [a,b] = [0,1]; console.log(a,b)
let [a,b,[c]] = [0,1,[3]] console.log(a,b,c)
|
左右两边模式不完全相同,可以成功赋值部分:
1 2 3 4 5 6 7 8
| let [a,b,c] = [0,1]; console.log(a,b,c)
let [a,b] = [0,1,2]; console.log(a,b)
let [a,...b,c] = [0,1,2,3]; console.log(a,b,c)
|
事实上,只要某种数据结构具有 Iterator 接口(后面会说到),都可以采用数组形式的解构赋值:
1 2 3 4 5 6 7 8 9 10
| function* fibs() { let a = 0; let b = 1; while (true) { yield a; [a, b] = [b, a + b]; } } let [first, second, third, fourth, fifth, sixth] = fibs(); console.log(first, second, third, fourth, fifth, sixth)
|
默认值
首先,ES6允许解构赋值指定默认值,但是必须当值严格相等于undefined才会生效:
1 2 3 4 5 6 7 8
| let [a = 1] = []; console.log(a);
let [b = 1] = [null]; console.log(b);
let [c = 1] = [undefined]; console.log(c);
|
结构复制可以引用其它变量,但必须声明过:
1 2 3 4 5
| let [x = y, y = 1] = [undefined, 1]; console.log(x, y);
let [x = 1 , y = x] = [10]; console.log(x,y);
|
默认值可以是一个函数:
1 2 3 4 5
| function f() { return 10; } let [x = f()] = []; console.log(x);
|
## 对象的解构赋值
#### 基本用法
可以看到,对象解构赋值,对于顺序没有要求,如果能找到与变量名称相同的`key`值,就赋值,找不到就是`undefined`
1 2 3 4 5 6 7 8
| let { a, b, c } = { a: 1, b: 2, c: 3 } console.log(a, b, c);
let { c, b, a } = { a: 1, b: 2, c: 3 } console.log(a, b, c);
let { a, c, b } = { a: 1 } console.log(a, b, c);
|
如果想要赋值的变量名和对象的`key`值不相同:
1 2
| let { a: obj1, b: obj2, c: obj3 } = { a: 1, b: 2, c: 3 } console.log(obj1, obj2, obj3);
|
对象也可以嵌套赋值,下面的代码中`p`和`y`都是模式,`x`和`obj2`才是变量:
1 2 3 4 5 6 7 8
| let obj = { p: [ 'Hello', { y: 'World' } ] }; let { p: [x, { y: obj2 }] } = obj; console.log(x, obj2);
|
#### 默认值
对象的解构赋值也可以设置默认值,生效条件是,对象的属性严格相等与`undefined`:
1 2 3 4 5 6 7 8
| let { a, b = 12 } = { a: 1 }; console.log(a, b);
let { a: obj1, b: obj2 = 12 } = { a: 11, b: undefined }; console.log(obj1, obj2);
let { a: obj1, b: obj2 = obj1 } = { a: 12 }; console.log(obj1, obj2);
|
## 字符串解构赋值
字符串被转换成了一个类似数组的对象:
1 2 3 4 5
| const [a, b, c, d, e] = 'hello'; console.log(a, b, c, d, e);
const { 0: a, 1: b, 2: c, 3: d, 4: e, length: len } = 'hello'; console.log(a, b, c, d, e, len);
|
可以看到,字符串即可以作为数组也可以作为对象解构赋值,但是当做对象时,还可以获取到`length`属性。
## 数值和布尔值的解构赋值
规则是,只要等号右边的值不是对象或数组,就先将其转为对象:
1 2 3 4 5
| let { __proto__: s } = Object(123); console.log(s === Number.prototype);
let { __proto__: s } = Object(true); console.log(s === Boolean.prototype)
|
看过我之前写的那篇原型链的文章,应该能看懂上面的代码。
## 函数参数的解构赋值
函数的参数也可以使用解构赋值,规则和上面的相同。
1 2 3 4
| function a([x, y = 1], { z, c }) { console.log(x, y, z, c) } a([1, 2], { z: 3, c: 4 })
|
## 用途
这部分内容,没什么好说的,拷贝忍者上线~
#### 交换变量值
1 2 3 4
| let x = 1; let y = 2;
[x, y] = [y, x];
|
#### **从函数返回多个值**
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
function example() { return [1, 2, 3]; } let [a, b, c] = example();
function example() { return { foo: 1, bar: 2 }; } let { foo, bar } = example();
|
函数参数的定义
1 2 3 4 5 6 7
| function f([x, y, z]) { ... } f([1, 2, 3]);
function f({x, y, z}) { ... } f({z: 3, y: 2, x: 1});
|
提取 JSON 数据
1 2 3 4 5 6 7 8 9 10
| let jsonData = { id: 42, status: "OK", data: [867, 5309] };
let { id, status, data: number } = jsonData;
console.log(id, status, number);
|
函数参数的默认值
1 2 3 4 5 6 7 8 9 10 11
| jQuery.ajax = function (url, { async = true, beforeSend = function () {}, cache = true, complete = function () {}, crossDomain = false, global = true, // ... more configs } = {}) { };
|
遍历 Map 结构
任何部署了 Iterator 接口的对象,都可以用for...of循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。
1 2 3 4 5 6 7 8 9
| const map = new Map(); map.set('first', 'hello'); map.set('second', 'world');
for (let [key, value] of map) { console.log(key + " is " + value); }
|
输入模块的指定方法
1
| const { SourceMapConsumer, SourceNode } = require("source-map");
|