ES6 允许按照一定模式, 从数组和对象中提取值, 对变量进行赋值, 这被称为解构.
一, 数组的解构赋值
1. 基本用法
- // 以前为变量赋值的写法
- let a = 1;
- let b = 2;
- let c = 3;
- //ES6 允许这样写
- let [a, b, c] = [1, 2, 3];
- b; //2
上面的代码表示可以从数组中提取值, 按照对应位置, 对变量赋值. 本质上, 这种写法属于 "模式匹配", 只要等号两边的模式相同, 左边的变量就会被赋予对应的值. 例如:
- let [foo, [[bar],baz]] = [1,[[2],3]];
- foo;//1
- bar;//2
- baz;//3
- let [, , third] = ["foo", "bar", "baz"];
- third;// "baz"
- let [x, y, ...z] = ['a'];
- x;//"a"
- y;//undefined
- z;//[]
如果解构不成功, 变量的值就等于 undefined.
如果等号的右边不是数组 (或者严格说不是可遍历的解构), 那么将会报错. 例如:
- let [foo] = 1;
- let [foo] = false;
- let [foo] = NaN;
- let [foo] = undefined;
- let [foo] = null;
- let [foo] = {};
2. 默认值
解构赋值允许指定默认值. 例如:
- let [foo = true] = [];
- foo;// true
- let [x, y = 'b'] = ['a'];
- x;//'a'
- y;//'b'
注: ES6 内部使用严格相等运算符 (===), 判断一个位置是否有值. 所以, 只有当一个数组成员严格等于 undefined , 默认值才会生效. 例如:
- let [x, y = 'b'] = ['a', undefined];
- x;//'a'
- y;//'b'
- let [x = 1] = [null];
- x;//null
如果一个数组成员是 null , 默认值就不会生效.
默认值可以引用解构赋值的其他变量, 但该变量必须已经声明.
- let [x = 1, y = x] = [1, 2];
- x;//1
- y;//2
- let [x = y, y = 1] = [];//ReferenceError: y is not defined
- let [x = y, y = 1] = [1, 2];
这里报错是因为, x 对应的组员是 undefined,x 的默认值生效, 但是默认值是 y, 此时 y 还没有声明.
二, 对象的解构赋值
1. 基本用法
- let {foo, bar} = {bar: 'bbb',foo: 'aaa'}
- foo;//'aaa'
- bar;//'bbb'
- let {baz} = {foo: 'aaa', bar: 'bbb'}
- baz;//undefined
对象的解构与数组的解构, 一个重要的不同点在于: 数组元素是按次序排列的, 变量的取值由它的位置决定; 而对象的属性没有次序, 变量名与属性同名, 才能取到正确的值.
如果没有与变量名对应的属性名, 导致取不到值, 最后等于 undefined.
2. 默认值
对象的解构也可以指定默认值. 默认值生效的条件是对象的属性值严格等于 undefined.
- let {x, y = 5} = {x: 1};
- x;// 1
- y;// 5
- let { message: msg = 'Something went wrong' } = {};
- msg;//"Something went wrong"
3. 解构失败
如果解构失败, 变量的值等于 undefined. 如果解构的是嵌套的对象, 而子对象所在的父属性不存在会报错.
- let {foo} = {bar: 'baz'};
- foo;//undefined
- // 报错
- let {foo: {bar}} = {baz: 'baz'};//TypeError: Cannot destructure property `bar` of 'undefined' or 'null'.
- // 这是因为解构的时候, foo 等于 undefined, 再取子属性就会报错.
如果要将一个已经声明的变量用于解构赋值, 需要注意:
- let x;
- {x} = {x:1};
- // 上面的代码会报错, 因为 JavaScript 引擎会将 {x} 理解为一个代码块, 从而发生语法错误. 只有不将大括号写在行首, 避免 JavaScript 将其解释为代码块, 才能解决这个问题.
- // 正确的写法
- let x;
- ({x} = {x:1});
三, 字符串的解构
字符串也可以解构赋值, 这是因为字符串被转成一个类似数组的对象.
- let [a,b,c,d] = 'hello';
- a;// "h"
- b;// "e"
- c;// "l"
- d;// "l"
类似数组的对象都有一个 length 属性, 因此还可以对这个属性解构赋值.
- let {length: len} = 'hello';
- len;// 5
四, 数值和布尔值的解构赋值
解构赋值时, 如果等号右边是数值或布尔值, 则会先转化为对象.
- let {toString: s} = 123;
- s === Number.prototype.toString; // true
- let {toString: s} = true;
- s === Boolean.prototype.toString; // true
上面代码中, 数值和布尔值的包装对象都有 toString 属性, 因此变量 s 都可以取到值.
解构赋值的规则是, 只要等号右边的值不是对象或数组, 就先将其转化为对象. 由于 undefined 和 null 无法转化为对象, 所以对他们进行解构赋值都会报错.
- let {prop: x} = undefined; // TypeError: Cannot destructure property `prop` of 'undefined' or 'null'.
- let {prop: y} = null; // TypeError: Cannot destructure property `prop` of 'undefined' or 'null'.
五, 函数参数的解构赋值
函数的参数也可以使用解构赋值.
- function add([x, y]) {
- return x + y;
- }
- add([1, 2]); // 3
上面代码中, 函数 add 的参数看似是一个数组, 但在传入参数时, 数组参数就解构为变量 x 和 y. 对于函数内部代码来说, 参数就是 x 和 y.
函数参数的解构也可以使用默认值.
- function move({x=0, y=0}={}) {
- return [x, y];
- }
- move({x:3,y:8});// [3, 8]
- move({x:3});// [3, 0]
- move({});// [0, 0]
- move();// [0, 0]
上例中, 函数 move 的参数是一个对象, 通过对这个对象进行解构, 得到变量 x 和 y 的值. 如果解构失败, x 和 y 等于默认值.
注意这种写法:
- function move({x, y} = {x: 0, y: 0}) {
- return [x,y];
- }
- move({x: 3,y: 8});// [3, 8]
- move({x: 3}); // [3, undefined]
- move({}); // [undefined, undefined]
- move(); // [0, 0]
上面的代码是为函数 move 的参数指定默认值, 而不是为变量 x 和 y 指定默认值.
六, 解构的用途
1. 交换变量的值
- let x = 1;
- let y = 2;
- [x, y] = [y, x];
- x;// 2
- y;// 1
2. 从函数返回多个值
函数只能返回一个值, 如果要返回多个值, 只能将它们放在数组或对象里面返回. 有了解构赋值, 取出这些值就非常方便.
- // 返回一个数组
- function example() {
- return [1, 2, 3];
- }
- let [a, b, c] = example();
- a;//1
- b;//2
- c;//3
- // 返回一个对象
- function example(){
- return {
- foo: 1,
- bar: 2
- }
- }
- let {foo, bar} = example();
- foo;//1
- bar;//2
3. 函数参数的定义
解构赋值可以方便的将一组参数与变量名对应起来.
- // 参数是一组有序值
- function f([x, y, z]) {}
- f([1, 2, 3]);
- // 参数是一组无序值
- function f({x, y, z}) {}
- f({x: 1, y: 2, z: 3});
4. 提取 JSON 数据
- let data = {
- id: 1,
- status: 'ok',
- data: [867, 5612]
- };
- let {id, status, data:number} = data;
- console.log(id, status, number);// 1 "ok" [867, 5612]
5. 遍历 Map 解构
- const map = new Map();
- map.set('first','hello');
- map.set('second','world');
- for (let [key, value] of map) {
- console.log(key + 'is' + value );
- }
- //first is hello
- //second is world
- // 获取键名
- for (let [key] of map) {
- }
- // 获取键值
- for (let [,value] of map) {
- }
来源: http://www.qdfuns.com/article/46690/2fe6d46c1ab9d109abedf2e9ffb8ac2d.html