十年踪迹

ES6 虽好,使用需谨慎

十年踪迹 · 2016-12-06翻译 · 1151阅读 原文链接

几天前我看到一条令人忍俊不禁的 tweet。

看到上面那段代码,我脑补了一个场景:

“让我们使用新潮的 ES6 解构”

“它看起来好难懂”

“别怕!我会为它添加一个注释”

这的确搞笑,但同时它这是一种典型的货物崇拜编程 —— 盲目而仪式性地使用代码或程序结构。你也许觉得上面的例子是一个特定的 case,一段新奇而在现实中不会存在的代码,但是让我们从一个实际项目里来看一段代码,这个项目叫 Calypso,它在 GitHub 上获得了超过 8000 的 star 数。

Calypso 是最新的 WrodPress.com 前端,它重新设计了一个漂亮的 WordPress dashboard,使用单页应用的形式,采用了 WordPress 的 REST API。Calypso 让你能够在同一处阅读、书写和管理你的 WordPress 站点。

这个项目在技术选型上非常激进,它使用了 react、redux、webpack、babel 以及 其他 150 个 npm 包,依赖了这么多新潮技术,它的参与者们应当可以写现代的、干净的、易于阅读和高可维护性的代码,不是吗?让我们看一下。不过在这之前,如果你对 redux 不熟悉,这里有一些速成课 —— reducer 是一个 纯函数,它接受两个参数,对其进行某些运算然后返回新对象,它基本上就是这么一回事。一个基础的 reducer 例子如下,它添加一个新的项到 TODO list 里:

多个 reducer 可以被组合在单个对象中,对象的属性名是各个 reducer 的名字,对应属性值是 reducer 函数。下面给出一段代码,它是众多 Calypso reducer 中的一个,我稍微改动了一点点,原始代码在这里

要弄明白上面这段代码究竟在做什么,你要花多长时间?如果你一下子就看明白了,那么恭喜你,你是真正的 JavaScript 忍者,因为,小伙子,你看,这段代码最大程度上使用了 ES6 甚至 ES7!

但是对于我,和许多像我一样的程序员,都会觉得上面那段代码像是行为艺术,它太难理解了,而如果我要实现同样的功能,我会用有点不同的方式来实现。这个 reducer 其实是用来在给定的网站上更新一篇已发表文章的状态,那么我们可以这么写:

而如果你认为两个版本不同只是个人品位问题,那么让我来分析一下原版那段胡里花哨的代码中更严重的问题。首先,不管是原版还是我这一版代码都需要被“编译”成老版本浏览器能够支持的 JavaScript,我将通过 Babel REPL 生成的代码大小对比如下(点击“完整代码”查看编译后的代码):

  • 原版 —— 完整代码:2012 字节,压缩后:1524 字节。
  • 我的版本 —— 完整代码:1390 字节,压缩后:1019 字节。

两者的不同看起来可能很小,但是在像 Calypso 这样的庞大项目里,类似上面那样的代码如果没有成千上万行也有成百上千行,它们若全部以货物崇拜的方式书写,可能会让 JS 脚本的大小显著增加,而这是我们为了优化关键渲染路径需要极力避免的。

此外,我修改过的这一版 reducer 运行得更快。我把 JSPerf 测试放在一起对比来证明我的版本比较快,下面是两个版本的测试在 chrome 中的运行结果截屏:

注意到我这一版代码也使用了 ES6 特性,但是它并没有过分追求花哨地去尝试使用每一个时髦特性,最终写出来的代码也更易读,更快和更小。而且我甚至还可以进一步优化它!让我用我最喜欢的编程语录来结束这篇文章。

在写代码时要想象最终维护你的代码的人是个有暴力倾向的精神病患者,而且他知道你住在哪儿(这样你就能更谨慎地写好代码了)。

John F. Woods, 1991 年 11 月