您当前的位置:首页 > 微信小程序开发笔记 >

JavaScript解构赋值

来源:JavaScript权威指南第7版0

ES6实现了一种复合声明与赋值语法,叫作解构赋值(destructuring assignment)。在解构赋值中,等号右手端的值是数组或对象(“结构化”的值),而左手端通过模拟数组或对象字面量语法指定一个或多个变量。在解构赋值发生时,会从右侧的值中提取(解构)出一个或多个值,并保存到左侧列出的变量中。解构赋值可能最常用于在const、let或var声明语句中初始化变量,但也可以在常规赋值表达式中使用(给已声明的变量赋值)。而且,解构也可以在定义函数参数时使用。下面是解构数组值的一段示例代码:

let [x,y]=[1,2];  //相当于let x=1,y=2
[x,y]=[x+1, y+1]; //相当于x=x+1,y=y+1
[x,y]=[y,x];      //交换两个变量的值
console.log(x,y);

前面我们看到了,可以在JavaScript的各种for循环中声明变量和常量。同样也可以在这个上下文中使用变量解构赋值。下面这段代码循环遍历了一个对象所有属性的名/值对,并使用解构赋值将两个元素的数组转换为单个变量:

let o={x:1, y:2};
for(const [name,value] of Object.entries(o)){
  console.log(name, value);
}

解构赋值左侧变量的个数不一定与右侧数组中元素的个数相同。左侧多余的变量会被设置为undefined,而右侧多余的值会被忽略。左侧的变量列表可以包含额外的逗号,以跳过右侧的某些值:

let [x,y]=[1];     console.log(x,y); //打印1 undefined
[x,y]=[1,2,3];     console.log(x,y); //打印1 2
[,x,,y]=[1,2,3,4]; console.log(x,y); //打印2 4

在解构赋值时,如果你想把所有未使用或剩余的值收集到一个变量中,可以在左侧最后一个变量名前面加上3个点(...):

let [x,...y]=[1,2,3,4];
console.log(x,y);
//打印1 [2,3,4]

解构赋值可用于嵌套数组。此时,赋值的左侧看起来也应该像一个嵌套的数组字面量:

let [a, [b,c]]=[1, [2,2.5], 3];
console.log(a,b,c);
//打印1 2 2.5

数组解构的一个强大特性是它并不要求必须是数组!实际上,赋值的右侧可以是任何可迭代对象,任何可以在for/of循环中使用的对象也可以被解构:

let [first, ...rest]="Hello";
console.log(first,rest);
//打印H ["e","l","l","o"]

解构赋值在右侧是对象值的情况下也可以执行。此时,赋值的左侧看起来就像一个对象字面量,即一个包含在花括号内的逗号分隔的变量名列表:

let transparent={r:0.0, g:0.0, b:0.0, a:1.0};
let {r,g,b}=transparent;
console.log(r,g,b);

下面这个例子展示了如何把Math对象的全局函数复制到变量中,这样可以简化需要大量三角计算的代码:

//相当于const sin=Math.sin, cos=Math.cos, tan=Math.tan;
const {sin, cos, tan}=Math;

注意,代码中Math对象的属性远远不止解构赋值给个别变量的这3个。那些没有提到名字的属性都被忽略了。如果赋值的左侧包含一个不是Math属性的变量名,该变量将被赋值undefined。在上面每个对象解构的例子中,我们都选择了与要解构对象的属性一致的变量名。这样可以保持语法简单且容易理解,但这并不是必需的。对象解构赋值左侧的每个标识符都可以是一个冒号分隔的标识符对,其中第一个标识符是要解构其值的属性名,第二个标识符是要把值赋给它的变量名:

//相当于const cosine=Math.cos, tangent=Math.tan;
const {cos:cosine, tan:tangent}=Math;

我发现如果变量名和属性名不一样,对象解构语法会变得过于复杂,反而导致用处不大。所以在这种情况下我通常不会使用简写形式。如果你选择使用,要记住属性名一定是在冒号左侧,无论是在对象字面量中,还是在对象解构赋值的左侧。在使用嵌套对象、对象的数组,或数组的对象时,解构赋值甚至会变得更复杂,但都是合法的:

let points=[{x:1,y:2}, {x:3,y:4}]; //两个坐标点对象的数组
let [{x:x1,y:y1}, {x:x2,y:y2}]=points;  //解构到4个变量中
(x1===1 && y1===2 && x2===3 && y2===4); //true

如果不是解构对象的数组,也可以解构数组的对象:

let points={p1:[1,2], p2:[3,4]}; //有两个数组属性的对象
let {p1:[x1,y1], p2:[x2,y2]}=points;
(x1===1 && y1===2 && x2===3 && y2===4); //true

类似这样的复杂解构语法既难写又难理解,甚至还不如使用类似 let x1=points.p1[0]; 这样的传统代码更简单易懂。

理解复杂解构

如果你发现自己维护的代码中使用了复杂的解构赋值,可以通过一些规律来应对这种复杂性。首先,想象一下常规(单值)赋值。在赋值之后,你可以从赋值的左侧取得变量名,然后在自己的代码中作为表达式使用,这个表达式会被求值为赋给它的值。解构赋值其实也一样。解构赋值的左侧看起来像是一个数组字面量或对象字面量。在赋值之后,左侧也类似于一个有效的数组字面量或对象字面量。为验证你写的解构赋值是正确的,可以尝试在另一个赋值表达式的右侧使用解构赋值的左侧:

//先定义一个数据结构并进行复杂的解构赋值
let points=[{x:1, y:2}, {x:3, y:4}];
let [{x:x1, y:y1}, {x:x2, y:y2}]=points;

//通过翻转赋值的两端来验证你的解构语法
let points2=[{x:x1, y:y1}, {x:x2, y:y2}];
console.log(points2===points);

建站咨询

在线咨询真诚为您提供专业解答服务

咨询热线

137 1731 25507×24小时服务热线

微信交流

二维码终于等到你,还好我没放弃
返回顶部