踩坑指南:JavaScript解构赋值

踩坑指南:JavaScript解构赋值

开篇

自从 2015 年ES6发布之后,到现在在项目中使用ES6语法应该是基本的操作,比如:const let class => 等等,就在今天我在使用 ES6 的解构赋值的时候翻车了...

以下是翻车现场

在项目开发中我经常使用解构赋值来获取 Object 的属性或者 Array的值

# 要解构属性的对象const result = { a: 'a', b: 'b' }# 使用解构来获取 a 和 bconst { a, b } = result
# 要解构的数组const list = [1, 2, 3]const [item, ...rest] = list

然而在项目中解构null 属性的对象的时候翻车了

# 后台返回的数据时这样的{  username: '',  identity: 'admin',  avatar: null,  token: 'f0a74a994e84e8ed3be11ed9f4bb5417'}

然后在解构数据的时候为 avatarusername 设置了默认值

const { username = '默认用户', identity = 'ADMIN', avatar = 'https://unavatar.now.sh/github/hom' } = result

在接下来使用avatar 的时候,发现值为 nullavatar没有赋值为默认的属性,导致后面的vuex赋值报错。而当我将赋值语句更改为ES5的赋值默认值语法的时候运行正常

const avatar = result.avatar || 'https://unavatar.now.sh/github/hom'

然后我就去查看 MDN关于解构赋值的文档,大概知道了为什么。这里也建议如果开发中对Javascript或者CSS有疑惑的地方,首选应该去查看MDN的文档

什么是解构赋值

解构赋值语法是一种 Javascript 表达式。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。

JavaScript开发中我们会频繁使用 objectarray的值,按照以往使用其值得方式是通过.或者[]来使用,而在 ES6中有新的方式去使用,就是解构赋值。

基本使用

常用的使用方式就是以字面量[]或者{}来获取 array或者 object的值

数组解构赋值

let a, b, rest;[a, b] = [10, 20];console.log(a);// expected output: 10console.log(b);// expected output: 20[a, b, ...rest] = [10, 20, 30, 40, 50];console.log(rest);// expected output: Array [30,40,50]

对象解构赋值

({ a, b } = { a: 10, b: 20 });console.log(a); // 10console.log(b); // 20({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40});console.log(a); // 10console.log(b); // 20console.log(rest); // {c: 30, d: 40}

常规用法

使用解构赋值经常使用到默认值的赋值,和使用 function的默认参数一样,使用 = 来添加属性的默认值

let a, b;[a=5, b=7] = [1];console.log(a); // 1console.log(b); // 7
let {a = 10, b = 5} = {a: 3};console.log(a); // 3console.log(b); // 5

问题

本篇文章出现的原因就是在使用解构赋值绑定默认值的时候出现了预期之外的结果。我们在解构源对象不存在的属性设置默认值得时候是没有问题的,但是在解构源对象已有属性,属性的值决定了我们设置默认值是否成功

现象

const { a = '1', b = '2' } = { a: 'a' }# output:# a = 'a'# b = '2'const { a = '1', b = '2' } = { a: 'a', b: null }# output:# a = 'a'# b = nullconst { a = '1', b = '2', c = '3', d = '4', e = '5' } = let object = { a: 'a', b: null, c: undefined, d: false, e: '' }# output:# a = 'a'# b = null# c = '3'# d = false# d = ''

我们可以看到只有值在 undefined 的时候默认赋值才能够赋值成功,而当我们使用 ES5 的语法来绑定默认值和解构赋值的结果有些不一样

const result = { a: 'a', b: null, c: undefined, d: false, e: '' }# alet a = result.a || '1'# output: a = 'a'# blet b = result.b || '2'# output: b = '2'# clet c = result.c || '3'# output: c = '3'# dlet d = result.d || '4'# output: d = '4'# elet e = result.e || '5'# output: e = '5'

是不是有一些意外,使用 ES5 方式的默认赋值和解构赋值的结果不一样,ES5 赋值的属性值为null undefined false '' 的时候均能够赋值默认值

思考

在看到赋值的结果的时候我们需要思考一下为什么会出现这样的结果,3 分钟......

解构赋值

MDN的文档中我们看到这样一句话

为了防止从数组中取出一个值为undefined的对象,可以在表达式左边的数组中为任意对象预设默认值。

对象的默认值绑定是在 array 的基础中添加的功能。什么时候会出现值为undefined 的属性名呢?答案是没有定义这个变量或者变量的值设置为 undefined的时候,而null '' false 在变量解析的过程中都是有值得情况,所以我们默认赋值会不成功,这儿可以参考一下函数的默认值

function (a, b = '2') {  // function content}

使用函数的默认值得时候,只要在当前的函数位置有参数,默认值解析式就会跳过默认值赋值,所以不管你是null还是'',都按照原始格式传入函数中。

所以我们在之后的开发中,如果只是根据属性的存在与否来绑定默认值的时候,可以使用解构赋值

使用||赋值

ES5 中的默认赋值我们会使用要判断的属性名加上||再加上默认值来绑定

const a = result.a || '1'

也正是由于使用了 || 来判断对象值得存在与否,所以只要对象的属性值能够转换为booleanfalse,默认值绑定就会成功,所以上文中我们使用的null undefined false ''都可以赋值成功。

如果使用||来绑定默认值的时候,同样也需要注意一点,由于||是通过将值转换为truefalse来进行短路操作,所以如果对象的值本身就是false的时候,如果你的默认赋值是其他类型的值,比如我在实例中使用的'1'false或者是默认值为true

const result = { a: false }# 下面是错误的示例const is = result.a || true

在上面的示例中是否发现了什么问题?对,就是is的值无论什么时候都是true,而忽略了result的原始值,这一点是我们需要注意的,可能会导致一些不可复现的 bug

总结

在上面的讨论之后,我们发现之后再使用默认值绑定,可以通过解构赋值来确定属性值是否存在为undefined,随后在程序中使用||来判断是否需要对逻辑值为false的属性进行默认值绑定

const result = { a: '' }let { a, b = 'default b' } = resultlet a = a || 'default a'

使用示例代码所使用的方法我们就可以对我们想要绑定默认值得属性进行正确的操作了。

参考

  • MDN解构赋值的语法

更多内容

更多的内容请关注GitHub,知乎@大手印,或者关注我的公众号@全栈开发师,我会不定时分享一些全栈方向的开发内容,谢谢分享

image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343