ES6系列之变量的解构赋值

1.什么是解构?

ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。它在语法上比ES5所提供的更加简洁、紧凑、清晰。它不仅能减少你的代码量,还能从根本上改变你的编码方式。

2.数组解构

以前,为变量赋值,我们只能直接指定值,比如

let a = 1;
let b = 2; 
let c = 3;

现在可以用数组解构的方式来进行赋值

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

这是数组解构最基本类型的用法,还可以解构对象数组

// 对象数组解构
let [a, b, c] = [{name: 'jacky'}, {name: 'monkey'}, {name: 'houge'}];
console.log(a, b, c); // {name: 'jacky'}, {name: 'monkey'}, {name: 'houge'}

3.数组模式和赋值模式统一

这条可以理解为等号左边和等号右边的形式要统一,如果不统一解构将失败。

let [a, [b, c], d] = [1, [2, 3], 4];
console.log(a, b, c, d); // 1 2 3 4

 // 提取除第二、三个外的所有数值
let [a, , , d] = [1, 2, 3, 4];
console.log(a, d); //1 4
    
let [a, ...b] = [1, 2, 3, 4];
console.log(a, b); // 1 [2, 3, 4]
        
let [a, , , ...d] = [1, 2, 3, 4, 5];
console.log(a, d); // 1 [4, 5]

如果解构不成功,变量的值就等于undefined

let [a, b, c] = [2, 3];
console.log(a, b, c); // 2 3 undefined

let [c] = [];
console.log(c); // undefined

上述是完全解构的情况,还有一种是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组,解构依然可以成功。

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

let [a, [b], d] = [1, [2, 3], 4];
console.log(a, b, d); // 1 2 4

4.解构的默认值

解构赋值允许指定默认值。

let [a, b=2] = [1];
console.log(a, b); // 1 2

let [a=1, b=2, c, d=13] = [10, 11, 12];
console.log(a, b, c, d); // 10 11 12 13

5.对象的解构赋值

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。


// 对象解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而非前者。
let obj = { a: "aaa", b: "bbb" };
let { a: x, b: y } = obj; 
console.log(x, y); // aaa bbb

let { a, b } = { a: 'aaa', b: 'bbb' };
console.log(a, b); // aaa bbb

// 不按照顺序
let { b, a } = { a: 'test1', b: 'test2' }
console.log(a, b) // test1 test2


// 嵌套解构
let { obj: { name }} = { obj: { name: 'jacky', age: '22' } }
console.log(name) // jacky

// 稍微复杂的嵌套
let obj = {
    p: [
        'Hello',
        { y: 'World' }
    ]
};

let { p: [x, { y }] } = obj;
console.log(x, y); // Hello World

如果变量名与属性名不一致,必须写成下面这样。

var { foo: rename } = { foo: "aaa",bar: "bbb" };
console.log(rename); // aaa
console.log(foo); // Uncaught ReferenceError: foo is not defined

如果在解构之前就定义了变量,这时候再解构会出现问题。下面是错误的代码,编译会报错(因为js引擎会将{a}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免js将其解释成代码块,才能解决这个问题)

let a;
let obj = { a: "aaa" };
{a} = obj; // Uncaught SyntaxError: Unexpected token '='

要解决报错,使程序正常,这时候只要在解构的语句外边加一个圆括号就可以了

let a;
let obj = { a: "aaa" };
( {a} = obj );
console.log(a); // aaa

6.函数参数

函数的参数也可以使用解构赋值。

function add([x, y]){
  return x + y;
}

add([1, 2]); // 3

函数参数的解构也可以使用默认值。

function fn(x, y = 7) {
    return x + y;
}
console.log(fn(3)); // 10

7.字符串解构

字符串被转换成了一个类似数组的对象。

const [a, b, c, d, e, f] = "hello";
console.log(a); //h
console.log(b); //e
console.log(c); //l
console.log(d); //l
console.log(e); //o
console.log(f); //undefined

8.数值和布尔值的解构赋值

解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。

let {toString: s} = 0;
console.log(s === Number.prototype.toString); // true

let {toString: s} = true;
console.log(s === Boolean.prototype.toString); // true

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefinednull无法转为对象,所以对它们进行解构赋值,都会报错。

let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError

9.解构赋值的应用

1.交换变量的值

通常交换两个变量的方法需要一个额外的临时变量,如下

let a = 1;
let b = 2;
let temp;

temp = a;
a = b;
b = temp;

console.log(a, b); // 2 1

用ES6解构赋值的话,会变得很简洁

let a = 1;
let b = 2;
[a, b] = [b ,a];

console.log(a, b); // 2 1

2.从函数返回多个值

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。

// 返回一个数组
function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一个对象
function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

3.访问数组中元素

有种场景,比如有一个数组(可能为空)。并且希望访问数组的第一个、第二个或第n个项,但如果该项不存在,则使用指定默认值。
通常会使用数组的length属性来判断

const list = [];

let firstItem = 'hello';
if (list.length > 0) {
    firstItem = list[0];
}

console.log(firstItem); // hello

如果用ES6解构赋值来实现上述逻辑

const list = [];
const [firstItem = 'hello'] = list;

console.log(firstItem); // 'hello'

4.提取 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.遍历 Map 结构

任何部署了 Iterator 接口的对象,都可以用for...of循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。

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) {
  // ...
}

文章部分内容参考:阮一峰老师的《ECMAScript 6 入门》一书

Image placeholder
fander
未设置
  53人点赞

没有讨论,发表一下自己的看法吧

推荐文章
ES6系列之箭头函数全解析

引言ES6中允许使用箭头=>来定义箭头函数,是ES6中较受欢迎也较常使用的新增特性。本文将从箭头函数的基本语法,与普通函数对比,箭头函数不适用场景三个方面进行梳理。基本语法//箭头函数 letfunc

Salesforce 斥资157亿美元收购Tableau之变

昨天Salesforce的一项收购决定刷新了自己的最高纪录,据外媒报道,6月10日Salesforce将以157亿美元收购数据可视化分析公司Tableau。Salesforce表示收购Tableau旨

干货丨爱奇艺CDN IPv6系统配置

1.背景  IPv6是“InternetProtocolVersion6”(互联网协议第6版)的缩写,是互联网工程任务组(IETF)设计的用于替代IPv4的下一代IP协议。IPv4地址资源紧缺严重制约

Python教程-解压可迭代对象赋值给多个变量

问题 如果一个可迭代对象的元素个数超过变量个数时,会抛出一个ValueError。那么怎样才能从这个可迭代对象中解压出N个元素出来? 解决方案 Python的星号表达式可以用来解决这个问题。比如,你在

《Go语言程序设计》读书笔记(六) 基于共享变量的并发

竞争条件 在一个线性(就是说只有一个goroutine的)的程序中,程序的执行顺序只由程序的逻辑来决定。在有两个或更多goroutine的程序中,每一个goroutine内的语句也是按照既定的顺序去执

重新认识一下JS声明变量的六种方式吧

开始先说一下JS中有哪六种变量的声明方法吧,然后我们带着三个问号去看文章:what?how?where?六种声明变量的方法: var let const function import class 没

Bash技巧:使用参数扩展获取变量的子字符串和字符串长度

在bash中,通常使用${parameter}表达式来获取parameter变量的值,这是一种参数扩展(parameterexpansion)。Bash还提供了其他形式的参数扩展,可以对变量值做一些处

使用 ES6 写 Koa Web 项目

完整代码:传送门我们node.js只是实现了部分ES6的语法,所以为了让我们ES6的代码能100%在node.js下执行,必须使用我们的babel把ES6代码编译成nodejs可执行的代码。node环

ES6问答-async函数

async函数 async是什么?它和Genernator函数外观上的区别是什么? constasyncReadFile=asyncfunction(){ constf1=awaitreadFile

第 10 节:复合类型-5. 指针 -- 指针与指针变量 7. 结构体指针变量

7.结构体指针变量我们前面定义了指针指向了数组,解决了数组引用传递的问题。那么指针是否可以指向结构体,也能够解决结构体引用传递的问题呢?完全可以。\ 下面我们先来看一下,结构体指针变量的定义:\\ 也

“设备+云管”双管齐下 H3C WAS6100交换机评测

俗话说“好马配好鞍,好船配好帆”。搭配是门技术活,对于企业组网来讲亦是如此。现如今,网络已成为企业业务的主要动脉,网速的快慢直接影响公司的办公效率,网络安全问题也成为公司最大的威胁。受制于成本和规模,

dw cs6怎么保存为css格式

dwcs6怎么保存为css格式1、首先,打开DreamweaverCS6,新建一个css文档,选中“css”,点击确定按钮。2、将设计好的css样式放入该页面,@charset"utf-8";用来指定

日均5亿查询量的京东订单中心,为什么舍MySQL用ES?

京东到家订单中心系统业务中,无论是外部商家的订单生产,或是内部上下游系统的依赖,订单查询的调用量都非常大,造成了订单数据读多写少的情况。我们把订单数据存储在MySQL中,但显然只通过DB来支撑大量的查

Stack Overflow上188万浏览量的提问:Java 到底是值传递还是引用传递?

在逛StackOverflow的时候,发现了一些访问量像阿尔卑斯山一样高的问题,比如说这个:Java到底是值传递还是引用传递?访问量足足有188万+,这不得了啊!说明有很多很多的程序员被这个问题困扰过

云服务已占企业网络流量的85%

来自云安全公司Netskope的一份报告显示,云服务目前已占企业网络流量的85%。云服务落地加快,主要由跨组织的协作驱动,需要多个云服务来支撑。在前20个云服务中,云存储和协作应用占据了榜单首位,一些

Stack Overflow 上 370万浏览量的一个问题:如何比较 Java 的字符串?

在逛StackOverflow的时候,发现了一些访问量像喜马拉雅山一样高的问题,比如说这个:如何比较Java的字符串?访问量足足有370万+,这不得了啊!说明有很多很多的程序员被这个问题困扰过。PS:

1000亿文本信息,高并发MD5查询,这么大数据量的业务怎么弄?

==提问== 沈老师,你好,想请教一个身份证信息检索的问题。公司有一个每秒5万并发查询的业务,(假设)根据身份证MD5查询身份证信息,目前有1000亿条数据,纯文本存储,前几天看你写LevelDB,请

SQL优化案例-定位系统中大量的rollback(十八)

系统中logfilesync比较严重,查看存储都没有问题,logfileparallelwrite很低,时间分布直方图也没问题数据库中提交和回滚操作比较频繁,每秒1000多次,rollback占比1/

万万没想到,HashMap默认容量的选择,竟然背后有这么多思考!?

集合是Java开发日常开发中经常会使用到的,而作为一种典型的K-V结构的数据结构,HashMap对于Java开发者一定不陌生。在日常开发中,我们经常会像如下方式以下创建一个HashMap:Map ma

【Kubernetes系列】第5篇 Ingress controller – traefik组件介绍

1.概述为了能够让Ingress资源能够工作,在Kubernetes集群中必须至少有一个运行中的ingresscontroller组件。也就是说如果在kubernetes集群中没有一个ingressc

Stylus系列——webpack-spritesmith配合stylus使用示例

一、前言基于Webpack的CSSSprites实现方案,若是直接在html中调用雪碧图图标已经很方便,但是实际开发过程可能遇到需要在伪元素中使用雪碧图,或者需要hover切换另一个图标,这种情况下就

[Java 程序员眼中的 Linux] Linux 下常用压缩文件的解压、压缩

Linux下常用压缩文件的解压、压缩 常用压缩包解压命令整理 Linux后缀为.tar.gz格式的文件-解压 命令:tarzxvfXXXXXX.tar.gz Linux后缀为.bz2格式的文件-解压

【转】vue mounted 调用两次的解决办法

因为售后项目是vue框架,但是对vue没有什么实战经验,就一直从头排bug。最后发现当我把上面初始化方法注释,发现就请求结果是一位数值。就意识到是否mounted调用两次?网上一搜索果然验证了想法。下

Mac 跑代码报 Illegal key size 错误的解决方法

异常原因:如果密钥大于128,会抛出java.security.InvalidKeyException:Illegalkeysize异常.因为密钥长度是受限制的,java运行时环境读到的是受限的pol

{