豆皮粉儿们,又见面了,今天这一期,由字节跳动数据平台的「相逢在雨季」给大家讲一道面试题,关于由于ES6综合运用。
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”480″ data-rawheight=”480″ data-thumbnail=”https://pic2.zhimg.com/v2-4dd1af9c2ec5be2a3cd7594b4a439621_b.jpg” width=”480″ data-original=”https://pic2.zhimg.com/v2-4dd1af9c2ec5be2a3cd7594b4a439621_r.jpg” data-actualsrc=”https://pic2.zhimg.com/v2-4dd1af9c2ec5be2a3cd7594b4a439621_b.gif”>
本文作者:相逢在雨季
在面试的过程中,经常能看到候选人写熟练掌握或者精通ES6,那就拿一道题试一试你的掌握情况吧,题目其实非常简单,如下所示。
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1352″ data-rawheight=”1198″ width=”1352″ data-original=”https://pic4.zhimg.com/v2-f94055905a273b4543755972c35ccfef_r.jpg” data-actualsrc=”https://pic4.zhimg.com/v2-f94055905a273b4543755972c35ccfef_b.jpg”>
好多候选人一看题目,思路一下就有了,啪一下就写出来了,很快啊。先看下实现的最多的版本
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1400″ data-rawheight=”586″ width=”1400″ data-original=”https://pic3.zhimg.com/v2-ce310d69909314e7dc6648a4fa0a4a6e_r.jpg” data-actualsrc=”https://pic3.zhimg.com/v2-ce310d69909314e7dc6648a4fa0a4a6e_b.jpg”>
很标准的实现,不是吗,问这里面用到了哪些 ES6
的特性,可以看出,主要用到了三个,一个是箭头函数 =>
,一个是块级声明 let
,一个是常量声明 const
。
这里可以在顺手问一个拓展的考点,如何实现一个真正的const,因为这里的const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动, 那如何实现一个真正只能只读的对象呢,下面给出答案。
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1414″ data-rawheight=”522″ width=”1414″ data-original=”https://pic1.zhimg.com/v2-b6ebbae5c753b2126380fa1bf3489d64_r.jpg” data-actualsrc=”https://pic1.zhimg.com/v2-b6ebbae5c753b2126380fa1bf3489d64_b.jpg”>
着手ES6的改造
继续上面的题,其实如果单独问 ES6
有哪些新特性,很多人都能答出来很多,但是一旦运用到真正的代码编写中,就还是使用回老一套,其实就这道题而言比如 箭头函数
, 解构赋值
, 扩展运算符
, 使用表达式作为对象的属性名
, 等等这些 ES6
的特性都能运用其中,下面就把这些特性一一代入到这个题当中,来体验一下综合运用 ES6
的感觉吧。首先,先加上 解构赋值
, 解构赋值
可以很方便的从一个对象中取值,这里可以在取得数组中每一个对象的 key
, value
时运用上。
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1392″ data-rawheight=”514″ width=”1392″ data-original=”https://pic1.zhimg.com/v2-9c761f0314a9aca5969bd0b6f18749b8_r.jpg” data-actualsrc=”https://pic1.zhimg.com/v2-9c761f0314a9aca5969bd0b6f18749b8_b.jpg”>
在这里还可以顺带的把 for
循环改成 for...of
, for...of
可以遍历一个迭代器( iterator
), Array
本质上就是一个迭代器,因为它实现了迭代器接口。
这里又可以拓展的去问一个问题,标准三连,什么是迭代器?javascript都有哪些迭代器?如何实现一个迭代器?这个大家下来后自行回答
还是先继续改造代码。把解构的过程放在for…of上,代码就变得更简洁了一些。
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1384″ data-rawheight=”480″ width=”1384″ data-original=”https://pic2.zhimg.com/v2-48255957d6bcacb0337a2f128a05f705_r.jpg” data-actualsrc=”https://pic2.zhimg.com/v2-48255957d6bcacb0337a2f128a05f705_b.jpg”>
然后,可以加上 扩展运算符
了,对于一个对象来说, 扩展运算符
的作用是可以合并一个对象,在 ES6
的时代,也可以使用 Object.assign
。这两个方法其实都可以。但无论用哪个方法,都会遇到一个问题,属性是一个动态的变量,在 ES5
的时代,想把属性作为变量进行对象赋值,只能使用以下方式
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1374″ data-rawheight=”260″ width=”1374″ data-original=”https://pic2.zhimg.com/v2-3be135c37097f79e6cb63fe546a42121_r.jpg” data-actualsrc=”https://pic2.zhimg.com/v2-3be135c37097f79e6cb63fe546a42121_b.jpg”>
但 ES6
允许我们使用字面量的形式来完成这个事情,只需要给属性表达式加上一个 []
即可,现在组合使用 扩展运算符
和 对象属性表达式
来优化一下代码吧。
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1398″ data-rawheight=”468″ width=”1398″ data-original=”https://pic2.zhimg.com/v2-c96bccae77b44c9a254390ae23130475_r.jpg” data-actualsrc=”https://pic2.zhimg.com/v2-c96bccae77b44c9a254390ae23130475_b.jpg”>
或者
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1426″ data-rawheight=”494″ width=”1426″ data-original=”https://pic3.zhimg.com/v2-d639bfd0f542aefd01ad7eadae0a2cf2_r.jpg” data-actualsrc=”https://pic3.zhimg.com/v2-d639bfd0f542aefd01ad7eadae0a2cf2_b.jpg”>
这样就成功的把这些 ES6
的特性综合的运用上了,现阶段总结一下用到的 ES6
特性吧, const
, let
, 箭头函数
, 扩展运算符
, for...of
, 解构赋值
, 对象属性表达式
。算下来有 七
个了。
减少一些副作用
不过这还没有结束,题目中还有一个要求,尽可能的少去声明变量,减少副作用。除了函数声明所必须的声明 const
,剩下的还有两处显式声明,那最少可以把这种显式的声明减少到几个呢,答案实际上是 0
个,这时就需要去改动 for循环
了,因为 for循环
是肯定会有显示的 const
或者 let
声明的, for循环
本身就是命令式的编程方式,如果使用的是声明式的方式,那就可能会把显式声明变成参数的隐式声明,可以进一步提高代码的可读性和简洁性,这一点其实卡住了很多候选人。解决的思路其实可以转化为,如何把一个数组进行所谓的折叠( fold
),就是把数组的多项合并成一项,这里其实涉及到的是一个 ES5
的数组函数, reduce
,众所周知,对 reduce
的经典使用当然就是累加了。
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1462″ data-rawheight=”142″ width=”1462″ data-original=”https://pic2.zhimg.com/v2-d8ca9a27f49a5c4fcbaf3c7581bd59ad_r.jpg” data-actualsrc=”https://pic2.zhimg.com/v2-d8ca9a27f49a5c4fcbaf3c7581bd59ad_b.png”>
其实以类比的思想,把对应的数字换成数组中的对象,把累加换成提取 key
, value
,进行合并,那数组的合并就是一种变相的累加了。有了 reduce
,就可以更大的发挥 ES6
的结合性了。
整合代码
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1408″ data-rawheight=”242″ width=”1408″ data-original=”https://pic3.zhimg.com/v2-c8e5c5ebe487e3cecb794f8cda132652_r.jpg” data-actualsrc=”https://pic3.zhimg.com/v2-c8e5c5ebe487e3cecb794f8cda132652_b.jpg”>
最后的 return
其实也可以去掉,让代码可以在一行的空间就可以实现了,在箭头函数返回对象的时候加一个括号即可。
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1118″ data-rawheight=”200″ width=”1118″ data-original=”https://pic1.zhimg.com/v2-636bdf40293b97d658ab123ac41fc4c4_r.jpg” data-actualsrc=”https://pic1.zhimg.com/v2-636bdf40293b97d658ab123ac41fc4c4_b.jpg”>
至此,我们对这个题的改造就结束了,综合使用了 ES6
特性,以及减少了显式的声明。写出这样的代码,这道题的解答就可以毕业啦。
彩蛋时间
这就结束了吗,还没有,可以看出, ES6
虽然很强大,但是要掌握它还是要学习各种特性,而且还要综合一些 ES5
的特性结合在一起才能发挥出最好的功效,有没有本身就和谐统一的形式来做这个事情呢,其实是有的,坐稳了,我们要加速了。进入到声明式的世界,打开 函数式编程
的大门吧。
说起函数式编程( FunctionalProgram
),其实也是一项法则,入门的话,你们只需要记住下面几个公理和几个概念就可以了。类比小说《三体》的 黑暗森林法则
就是这么解释的。
- 函数是一等公民(
functionfirst
), FP
的世界只有函数
- 函数自身都有可组合的特性(
composition
),但函数本身是纯净( pure
)的
想要继续了解函数式编程,还有两个很重要的概念,柯里化( curry
)和 PointFree
针对 JS
函数式编程有一个很重要的工具库,对,它不是 lodash
而是 Ramda
,使用 Ramda
来做一下上面的题吧。
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”1388″ data-rawheight=”1200″ width=”1388″ data-original=”https://pic4.zhimg.com/v2-69303bfc16cf7746d76beaa2251adb77_r.jpg” data-actualsrc=”https://pic4.zhimg.com/v2-69303bfc16cf7746d76beaa2251adb77_b.jpg”>
乍一看代码,我大意了啊,没看懂,就像面壁者罗辑的咒语一样晦涩难懂和不可理喻对吧,但在某种程度上,即使只从表面来看,它又充满了和谐简洁的美,拥有高度的秩序排列和统一性,而且完全符合上面的 两条公理
和 两个重要概念
,如果大家对什么是函数式编程,它主要有那些概念,具体的应用场景有哪些感兴趣的话,我会另写一篇详细的讲一讲 函数式编程。
好书
推荐:
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”582″ data-rawheight=”842″ width=”582″ data-original=”https://pic2.zhimg.com/v2-ff1293718c877c6b3a208cae9185a339_r.jpg” data-actualsrc=”https://pic2.zhimg.com/v2-ff1293718c877c6b3a208cae9185a339_b.jpg”>
不识老尼,枉为前端攻城狮,其成名作《JS高级程序设计》曾名动江湖。深入理解ES6的特性对于所有JavaScript开发者而言至关重要,在可预见的未来,ES6中引入的语言特性会成为JavaScript应用程序的主流特性,这也是《深入理解ES6》的初衷。希望你通过阅读《深入理解ES6》可以了解ES6的新特性,并在需要时能够随时使用。
<img src="data:image/svg+xml;utf8,” data-caption=”” data-size=”normal” data-rawwidth=”516″ data-rawheight=”258″ data-thumbnail=”https://pic3.zhimg.com/v2-ad62d7a2f0db827c8ee16ee3b418b076_b.jpg” width=”516″ data-original=”https://pic3.zhimg.com/v2-ad62d7a2f0db827c8ee16ee3b418b076_r.jpg” data-actualsrc=”https://pic3.zhimg.com/v2-ad62d7a2f0db827c8ee16ee3b418b076_b.gif”>