小记3 - 1解构赋值:更高效的提取变量 - 解构数组

背景:解构(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

总结

本质上,解构赋值这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
数组的元素是按次序排列的,变量的取值由它的位置决定;

你可能感兴趣的:(小记3 - 1解构赋值:更高效的提取变量 - 解构数组)