写点什么

深入 JS 中几种数据类型的解构赋值细节

作者:猪痞恶霸
  • 2022 年 7 月 04 日
  • 本文字数:2313 字

    阅读完需:约 8 分钟

解构赋值

何为解构赋值


  • 解构:可以在数组或对象中的值分离出来

  • 赋值:将解构出来的数据对变量进行赋值


在 ES5 中的普通的变量赋值方法:


var a = 1;var b = 2;
复制代码


在 ES6 中的解构赋值方法,一句话解构赋值方法的过程即镜像,两边的互为镜像,相同位置变量和数值一一对应


let [a,b] = [1,2] // 等价于上述
复制代码


使用解构赋值方法可以将赋值变得灵活,下面将对解构赋值进行讲解

数组解构

嵌套解构

js 允许数组和对象的成员为数组或对象,所有当数组为嵌套数组的时候,依旧可以对数组进行解构赋值


let [a,[b],c] = [1,[1,2],3]console.log(a,b,c) // 1 1 3
复制代码

扩展运算符解构

在解构中可以使用...扩展运算符


let [a,...b] = [1,2,3,4]console.log(a,b)// a = 1 b = [2,3,4]
复制代码

不完全解构

两边不一定是完全匹配的,可以根据实际需要,对其进行解构赋值


let [, , a] = [1,2,3]console.log(a) // 3
复制代码

不成功的解构

当解构目标是其他类型的时候解构是不成功的


let [a] = 1console.log(a) // TypeError: 1 is not iterable
复制代码


又或者当目标赋值变量与右侧解构目标不匹配的时候,如下列,b的值为 undefined,所以解构也是不成功的


let [a,b] = [1]console.log(a,b) // 1 undefined
复制代码

关于interator

在不成功的解构中如果的解构目标为一个数值,那么抛出的错误为1 is not iterable,翻译一下:1 是不可被可迭代的,下面了解一下interator即迭代器和解构赋值的关系。


js 中内置了表示集合数据结构比如:Array,Object,两者都含有interator,而undefined,null,NaN等等是不包含interator的,解构赋值无法作用于不含有interator的数据结构,而所有包含interator的数据解构都可以被解构赋值

带有默认值的解构赋值

在不成功的解构中包含了不匹配的情况,而这种情况可以使用默认值来解决,无论是哪种类型的解构赋值都可以预先对变量进行赋值,避免不匹配而造成解构不成功的现象。


let [a,b=2] = [1]console.log(a,b) // 1 2let [c = 1] = [undefined]console.log(c) // 1
复制代码

关于undefined的问题

当对变量赋为默认值,解构目标数组内只含有一个 undefined 的情况下,变量最终会赋值为默认值,但是如果是NaNnull的情况下会是怎么样的。


let [c = 1] = [NaN]console.log(c) // NaNlet [c = 1] = [null]console.log(c) // null
复制代码


出现上述情况的原因是因为在 ES6 中使用的是===来判断一个位置是否含有值,造成了NaNnull不严格等于undefined的情况。

对象解构

与数组解构的不同

因为数组是有下标的,但是对象没有,对象只能依靠属性名,所以在对象的解构赋值时,变量名需要与解构对象中目标属性名一致


let {name} = {name:"猪痞恶霸"}console.log(name) // 猪痞恶霸
复制代码

变量名与属性名不一致

在重构前辈的代码的时候会遇到不可逆转的情况,所以我们可以使用:来解决这个不可逆转问题


let {name:difname} = {name:"猪痞恶霸"}console.log(difname) // 猪痞恶霸
复制代码


其实这里是根据解构模式的本质来即模式匹配来实现的,使用name来匹配对象中的属性来完成变量名的更改

多层嵌套对象的解构赋值

let people = {    name:"猪痞恶霸",    like:{        community:"juejin",        code:"js"    }}let {name,like:{code}} = peopleconsole.log(name,code) // 猪痞恶霸 js
复制代码


对象多层嵌套的话,可以根据一层一层的匹配来解构到所需的属性,比如上面想要拿到code,所以先匹配到like对象,再对like对象进行解构赋值拿到code

模式问题

经过上面的例子清楚了多层对象的解构方法,通过模式匹配来拿到下一层属性或者对象,那么这里的模式即like是不能够拿到值得,我们打印一下会出现like is not defined的问题,这个是需要注意的。

字符串解构

上面提到过可以被解构赋值的数据类型包括数组和对象等含有迭代器的数据类型,而字符串能够像前两者一样被解构,是因为在进行解构赋值的时候,字符串被转化为了一个类似数组的对象,一个类似数组的对象会是什么呢,下面来看一下。


let str = "猪痞恶霸"let {1:first} = strconsole.log(first) // 痞
复制代码


这是个很有意思的现象,通过模式匹配,使用 1 拿到痞,这个地方大致就能明白为什么叫一个类似数组的对象


除此之外还可以使用数组形式的解构方式


let str = "猪痞恶霸"let [a] = strconsole.log(a) // 猪
复制代码


我们还可以通过对象解构形式拿到字符串的属性,比如说字符串的长度


let str = "猪痞恶霸"let {length} = strconsole.log(length) // 4
复制代码

数值与布尔值解构

数值和布尔值能够被解构赋值的原因是因为在解构之前可以将其转化为对象


let { toFixed:a} = 123console.log(a)  // toFixed() { [native code] }
复制代码


可以直接解构出数值的一些方法和属性比如上述解构出toFixed方法

利用原型链判断

上面解构出toFixed方法,那么这里可以通过原型链来判断两者之间的异同


console.log(a === Number.prototype.toFixed) // true
复制代码


显而易见,两者是等价的,正如此说明在解构前数值会转变为对象形式,包含了其属性和通过原型得到的方法


布尔值的解构与数值解构相同

函数参数解构

函数参数解构其实是函数与之前解构的结合,至少我是这么认为的


function add([x,y]) {    return x+y}add([1,2]) // 3
复制代码


但是这种解构方式又有什么实际的作用,和普通的变量参数有什么区别,请看下面的例子


let arr = [[1,2],[2,3]]arr.map((item) => item[0]+item[1])
复制代码


我们使用 map 遍历一个嵌套数组,然后再将其每个成员数组内的成员相加,这是使用普通参数方法实现,那么来使用解构赋值看一下。


let arr = [[1,2],[2,3]]arr.map(([a,b]) => a+b)
复制代码


这样就很舒服,不需要复杂的下标来定位数组成员,直接使用解构赋值剥离即可。

解构的歧义

解构赋值的过程是需要判断模式表达式,无法预先知道,必须通过===来进行严格的判断才能拿到是什么进行下一步操作

参考文献

  • ES6 标准入门第三版

发布于: 20 小时前阅读数: 16
用户头像

猪痞恶霸

关注

还未添加个人签名 2022.07.01 加入

还未添加个人简介

评论

发布
暂无评论
深入JS中几种数据类型的解构赋值细节_前端_猪痞恶霸_InfoQ写作社区