ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构,当不是对象或者数组,那么解构时就会首先尝试将等号右边的内容转换为对象,因此也可以用于对字符串、布尔、数值进行解构赋值,而对于undefined、null值进行解构赋值则会报错,本文简要总结一下数组、对象、字符串、布尔及数值、函数参数的解构赋值等。
一、数组的解构赋值
数组的解构赋值就是按照数组中的次序对变量进行赋值,左边和右边的模式要匹配,如果不匹配,那么就会导致取到的值为undefined或者报错,但是也可以进行不完全解构,示例如下:
let [foo, [[bar], baz]] = [1, [[2], 3]];
//foo:1 bar:2 baz:3
let [ , , third] = ["foo", "bar", "baz"];
//third:baz
let [x, , y] = [1, 2, 3];
//x:1 y:3
let [head, ...tail] = [1, 2, 3, 4];
//head:1 tail:[2,3,4]
let [x, y, ...z] = ['a'];
//x:'a' y:undefined z:[]
//解构失败值为undefined
let [foo] = [];
let [bar, foo] = [1];
// foo:undefined
//不完全解构
let [x, y] = [1, 2, 3];
// x:1 y:2
let [a, [b], d] = [1, [2, 3], 4];
// a:1 b:2 d:4
当等号右边不是数组的时候,就会发生解构报错:
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
解构赋值允许使用默认值,默认值有效是在解构的过程中其值严格等于undefined的情况下,即使等于null,默认值也不会生效,如果默认值是一个表达式,那么这个表达式只有在用到的时候才会求值,也就是说如果能够直接取到值,那么就不会计算该表达式,示例:
let [foo = true] = [];
// foo:true
let [x, y = 'b'] = ['a'];
// x:'a' y:'b'
let [x, y = 'b'] = ['a', undefined];
// x:'a' y:'b'
let [x = 1] = [undefined];
// x:1
let [x = 1] = [null];
// x:null
function f() {
console.log('aaa');
}
let [x = f()] = [1];
// x:1,此时函数f并不会执行,因为x可以直接取到1
二、对象的解构赋值
数组的解构赋值是根据次序决定的,但是对象是无序的,因此要想成功赋值必须要求变量与对象的属性名一致,如果不一致就会得到undefined值,或者使用键值对的方式,将值设置为与属性名一致,如下:
let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
// bar:'bbb' foo:'aaa'
let { baz } = { foo: 'aaa', bar: 'bbb' };
// baz:undefined
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
// baz:'aaa'
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
// f:'hello' l:'world'
//上面第一种的解构赋值实际是下面形式的简写:
let { bar:bar, foo:foo } = { foo: 'aaa', bar: 'bbb' };
运用对象的解构赋值,可以很方便地将对象的函数赋值给变量:
let {sin,cos,log} = Math
嵌套结构的解构赋值:
const node = {
loc: {
start: {
line: 1,
column: 5
}
}
};
let { loc, loc: { start }, loc: { start: { line }} } = node;
// loc:Object {start: Object} start:Object {line: 1, column: 5} line:1
同数组一样,对象也可以设置默认值,默认值有效的条件是严格等于undefined:
var {x = 3} = {};
// x:3
var {x, y = 5} = {x: 1};
// x:1 y:5
var {x: y = 3} = {};
// y:3
var {x: y = 3} = {x: 5};
// y:5
var { message: msg = 'Something went wrong' } = {};
// msg: "Something went wrong"
var {x = 3} = {x: undefined};
// x:3
var {x = 3} = {x: null};
// x:null
将一个已经声明的变量进行解构赋值,要使用圆括号将等式两边括起来,否则会被认为是代码块,而导致报错:
let x;
{x} = {x: 1};
// SyntaxError: syntax error
//正确方式:
({x} = {x: 1})
三、字符串的解构赋值
解构之前,字符串会被转换为一个类似数组的对象:
const [a, b, c, d, e] = 'hello';
// a:"h"
// b:"e"
// c:"l"
// d:"l"
// e:"o"
类似数组的对象都有一个length属性,因此可以对其进行解构赋值:
let {length:len} = 'hello';
// len:5
四、数值和布尔值的解构赋值
同字符串,数值和布尔值会被转换为对象,例如它们都有toString方法,可以对其进行解构赋值:
let {toString: s} = 123;
s === Number.prototype.toString /true
let {toString: s} = true;
s === Boolean.prototype.toString //true
五、函数参数的解构赋值
函数参数也可以使用解构赋值,通过解构赋值,可以更方便地在函数中使用传入的变量,同时更方便为函数参数设置默认值,还可以使得在调用函数的时候不用传入参数也能正常运行,见下例:
function add([x, y]){
return x + y;
}
console.log(add([1, 2])); // 3
给函数参数设置默认值:
function move({x = 0, y = 0} = {}) {
return [x, y];
}
console.log(move({x: 3, y: 8})); // [3, 8]
console.log(move({x: 3})); // [3, 0]
console.log(move({})); // [0, 0]
console.log(move()); // [0, 0]
六、解构赋值的用途
1.交换变量的值
let x = 1;
let y = 2;
[x, y] = [y, x];
2.函数返回多个值
通过解构赋值,能够方便地取出函数返回的多个值,不过需要在函数中将多个值放在一个数组或对象里。
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
3.函数参数的定义
解构赋值能够方便地让一组参数与变量名对应起来:
function f([x, y, z]) {
return x + y + z
}
console.log(f([1, 2, 3])); //打印出6
4.提取JSON数据
解构赋值能够方便地提取出JSON对象中的数据:
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number); //42 'OK' [867,5309]
5.函数参数的默认值
指定参数的默认值,就避免了在函数体内部写var foo = config.foo || 'default foo' 这样的语句:
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
} = {}) {
// ... do stuff
};
6.遍历Map结构
解构赋值能够让遍历Map的键名或键值更加方便:
// 获取键名
for (let [key] of map) {
// ...
}
// 获取键值
for (let [,value] of map) {
// ...
}
7.输入模块的指定方法
加载模块时,往往需要指定输入哪些方法,解构赋值使得输入语句非常清晰
const { SourceMapConsumer, SourceNode } = require("source-map");
本文参考:ES6教程-网道:变量的解构赋值