背景:解构(destructuring)有何用?
let heros = {
no1: "吕布",
no2: "张飞",
weapons: [ "刀","剑","弓箭"]
};
// 从对象中提取数据
let lb = heros.no1, zs = heros.no2, weapons = heros.weapons;
想象一下,若heros中有100万个变量需要提取处理呢?若 是多层嵌套的数据结构呢?可能会为了一点数据而挖掘整个结构,做大量低效重复的工作。
解构赋值
解构赋值--使得把数据结构分解为更小的部分时,提取数据会变得更容易,更高效。
解构赋值语法是一种 Javascript 表达式。解构使用的语法--就是对象与数组的字面量语法。--按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
基本原则如下:
数组的元素是按次序排列的,变量的取值由它的位置决定;
对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
数组的解构赋值
1 变量声明并赋值时的解构 或者先声明变量再赋值
let foo = ["one", "two", "three"];
let [m, n, three] = foo;
console.log(m); // "one"
console.log(n); // "two"
console.log(three); // "three"
//-或者
let [foo, [[bar], baz]] = [1, [[2], 3]];
console.log(foo); // 1
console.log(bar); // 2
console.log(baz); // 3
//先声明再赋值
let a, b;
[a, b] = [1, 2];
注意1:在使用 var 、 let 、 const 进行数组解构时,必须提供初始化 器(即等号 右边的值)
const [a ,b];
let [d,e];
// Uncaught SyntaxError: Missing initializer in destructuring declaration
注意2:如果解构不成功,变量的值就等于undefined。
let [foo] = [];
let [bar, foo] = [1];
//以上两种情况都属于解构不成功,foo的值都会等于undefined。
注意3:不完全解构-等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。
let [x, y] = [1, 2, 3];// x//1 y //2
let [a, [b], d] = [1, [2, 3], 4];// a //1 b // 2 d // 4
注意4:解构报错--如果等号的右边不是数组(或者严格地说,不是可遍历的结构,不具备 Iterator 接口),那么将会报错。
// 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
2 忽略某些值,只对感兴趣值解构
let [ , , third] = ["foo", "bar", "baz"]; //逗号-, 为数组前面的项提供的占位符
console.log(third); // "baz"
3 默认值
ES6 解构内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。
const [a=5, b=7] = [1];
console.log(a); // 1
console.log(b); // 7 --默认值生效
let [x = 1] = [undefined];
x // 1 --默认值生效
let [x = 1] = [null];
x // null
注意1:如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
function f() {
console.log('aaa');
}
let [x = f()] = [1]; //因为x能取到值,所以函数f根本不会执行。
//上面的代码其实等价于下面的代码。
let x;
if ([1][0] === undefined) {
x = f();
} else {
x = [1][0];
}
注意2:默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
let [x = 1, y = x] = [2]; // x=2; y=2
let [x = y, y = 1] = []; // ReferenceError: y is not defined
//--因为x用y做默认值时,y还没有声明
4 剩余项 (...) -- 将剩余数组赋值给一个变量(数组)
当解构一个数组时,可以使用剩余模式,将数组剩余部分赋值给一个变量。
var [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3] --注意,这是个数组
注意:如果剩余元素右侧有逗号,会抛出 SyntaxError
,因为剩余元素必须是数组的最后一个元素,之后不能再有逗号,否则就是语法错误。
var [a, ...b,] = [1, 2, 3];
// SyntaxError: rest element may not have a trailing comma
应用1::若要取出特定项 并要求保留剩余的值,则剩余项是非常有用的。
应用2:方便地克隆数组在JS中是个明显被遗漏的功能。
在ES5中常用的concat()方法来克隆数组 (方便简单);在ES6中,使用剩余项的语法克隆数组(小技巧)
// 在 ES5 中克隆数组
let colors = [ "red", "green", "blue" ];
let clonedColors = colors.concat();
colors[2] = "skyblue";
console.log(clonedColors); //"[red,green,blue]"
concat()方法本意是合并两个数组,但不使用任何参数来调用此方法,会获得原 数组的一个克隆品。
// 在ES6中,使用剩余项的语法克隆数组 ,达到上述同样效果
let colors = [ "red", "green", "blue" ];
let [ ...clonedColors ] = colors;
colors[2] = "skyblue";
console.log(clonedColors); //"[red,green,blue]"
5 嵌套的数组 解构
在整个解构模式中插入另一 个数组模式,解构操作会下行到 嵌套的数组中。可以使用任意深 度的数组嵌套解构。
let colors = [ "red",[ "green", "lightgreen" ], "blue" ];
let [ firstColor, [ secondColor ] ] = colors;
console.log(firstColor); // "red"
console.log(secondColor); // "green"
应用篇
交换变量 - 在一个解构表达式中可以轻松交换两个变量的值。
//在 ES5 中互换值需要使用第三个变量作为临时变量:
let a = 1, b = 2, tmp;
tmp =a ; a = b; b = tmp;
console.log(a); // 2
console.log(b); // 1
// 在 ES6 中互换值
let a = 1, b = 2;
[ a, b ] = [ b, a ];
console.log(a); // 2
console.log(b); //1
解析一个从函数返回的数组
从一个函数返回一个数组是十分常见的情况。解构使得处理返回值为数组时更加方便。
function f() {
return [1, 2];
}
let a, b;
[a, b] = f();
console.log(a); // 1
console.log(b); // 2
总结
本质上,解构赋值这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
数组的元素是按次序排列的,变量的取值由它的位置决定;