本文建议结合 https://github.com/Tk-archer/functional-javaScript-code-refactoring 这个项目阅读查看
起
『JavaScript函数式编程』这书其实在几年前我就入手了,但是当时并没能读下去,然后就一直尘封在书柜里面。
直到最近才偶然翻出来,打算好好读一下。本文说是读书笔记的话就过于正式了,所以就只能称之为备忘录了。
为了避免重蹈覆辙,我总结上一次没能读下来的原因
- 只是读书,书本身不厚,但是里面有不少示例代码,大量的概念直接蕴含着代码当中,而且前后关联,当时顾着硬啃书,而没有去实践一下代码,当然就很难读进去了
- 代码语法偏差,书中的代码实际上是以 es5 为准实现的,虽然等价,但是习惯了 es6 以上的代码的时候,会明显感受到 es5 所带来的阅读理解成本
- 类库不一致,本书成型的时候还是 Underscore.js 流行的时候,而我读到这本书的时候已经是 lodash 的时代了,这两者之间的偏差也为我带来了理解上的成本
因此,我所想到的更加好的复读这本书的方法就是—— 用 es6 以上的语法,以及根据自己的理解将示例代码的实现都重构一遍。除了为了让自己阅读起来更加顺畅以外,我觉得重构代码的方式能让我静下心来,更加好地理解其代码中所要表达的思想。
而本文存在的意义便是记录那些在重构过程中的一些想法。
其一,模板字符串和数组拼接字符串
本书从第一章的代码实现开始,就存在着大量的形如 :
|
|
的代码。这个代码实际上就是一个拼接字符串而已,不过为啥用 array.join() 让我困惑了很久。然后根据我的一些猜测和考证,猜测是这样相当于把字符串封装到数组中, 可以通过一致的方式调用数组的处理函数(如果有需要的话)
因为里面有一句名言:
用100个函数操作一个数据结构,比用10个函数操作10个数据结构要好。
这是猜测,而考证出来更加实际方面的原因是——在旧时代中的浏览器中用 +
拼接字符串的性能十分糟糕,比如极端的 ie6 环境中能比 array.join()
的方式慢了 6 倍左右,关于这点可以参考这个 提问 。
因此考虑到成书使时间,使用 array.join()
很有可能是源于作者以前遗留下来的一种“良好”习惯。
不过,现代浏览器不仅有了更好的字符串拼接性能,而且 es6 中也有了更加简洁的语法,所以在我的重构中,上述代码就会变成:
|
|
其二,箭头函数与 rest 解构
这就是其中一个我所说的,阅读体验的问题了,一旦习惯了箭头函数,就很难不觉得满是 function
关键字的代码不够简洁,而本书中,经常会需要操作到 arguments ,有了 rest 析构,则可以进一步精简代码,让我们的注意力集中在需要的地方
|
|
箭头函数是个好文明
其三,_.pick 与 construct 与 rest
这个是 ep-2 里的一段代码,很的说明了其相互关联一面
|
|
可以看到 cat 的作用是将所有数组参数合并到一起,而 construst 则是将首参和第二个参数合并到同一个数组中
接着,如果完全按照原文中的逻辑重构,会有这样一段代码
|
|
这段代码也让我稍微纠结了一下,尤其是后面调用 construct
的地方有点让人困惑,实际上作者要这样写的原因是
- underscore 的 pick 的 keys 不支持 第二参数传入数组,只支持将 key 作为参数逐个传入
- 比如
_.pick({}, key1, key2, key3)
- 比如
- 为了展开 keys 数组作为 pick 的参数,所以会使用 apply ,而
construct
就是为了将 obj 也拼接到数组中,用作首参
|
|
因此这里有两个精简方法
|
|
这里同时也体现了 lodash 和 underscore 那些细微的差异,对代码理解时带来的困惑。
其四,chain 是个坏文明
在本书中,作者非常推崇 chain,因为 chain 可以将数据封装到一个一致的数据结构中,然后使用 underscore 中的种种便利的操作函数处理它,这非常好的体现了 用100个函数操作一个数据结构,比用10个函数操作10个数据结构要好 的想法。
|
|
然而,在现实中 chain 却不是一个良好的实践方案,它固然有好处,但是他带来的问题也同样明显。
关于这点可以看我翻译的这篇文章,作者详尽的介绍了为啥 chain 不是一个好的习惯
简单在这总结一下就是
- 为了调用到所有有可能使用到的函数,你需要将所有的函数绑定到原型上,这让类库体积飙增且难以精简。
- 为了迎合 chain 链式调用的方式,你需要使用一些相对复杂且不友好的方式才能对它进行扩展
因此,在我重构的代码中,我总是选择换一种方式实现,而非 chain,所幸的是我们其实不乏更好的,更加函数式的表达方式可以替代—— compose
|
|
结语
本文写在我已经重构了 4 章的代码的时候,大约一半左右,理论上应该还有一篇下,不过那应该是我将所有代码重构一遍之后的事情了。