来, 随手那一小段 anime.js 的代码。看其中最简单的一段:
str: a => typeof a === 'string',
这一句,就看得出作者遣词造句的能力。
比如,他用了三等号,就是 === ,而不是双等号 == 。这两个相等运算在这里都是可以使用的,运行结果其实是一样的,但是三等号更加准确的表达了这里作者想意图,就是要“严格相等,不仅仅值要相等,类型也要相等”。
类似这些,随手可见。细小的地方,看起来赏心悦目。而很多不严谨的代码,计算机执行起来没有问题,但是用词不够准确,总有帮他改正确的冲动。
再比如箭头函数的定义,还有 const 的使用。这些都是 ES6 的新方法,把原来的复杂的函数定义变得更加简洁,而作者也就很快的把本来需要好几行的代码变成了简洁的一行。
另外一个值得注意的,是一种类似排比的写法。本来判断一个变量是什么类型是一个相当琐碎的事情,因为正如这个函数写的那样,不同的类型用了完全不同的方法(这也是JavaScript不够优美的地方),判断是不是 数组要用 Array.isArray( ),而判断是不是字符串则用了完全不同的方法。
而这一小段代码搜罗了各种需要判断的类型,然后封装在一个轻巧的小函数里面,一段原来需要写做这样的代码:
if(stringContains(Object.prototype.toString.call(a), 'Object')) dosomething();
变成了
if(is.obj(a)) dosomething;
并且统一了所有的类型的调用。
同时,他还用了三个字母的代码来代表各种不同的类型,这三个字母的命名方式和国际机场的三位字母代码有异曲同工之妙,让代码简洁,整齐。不知道是不是只有我,我看着从上到下整齐的那一竖排 a ,还有像军队一样的 => 就有种莫名的兴奋。
这段代码很像一个勤劳的家庭主妇,把家里孩子乱七八糟的玩具收纳到一个个抽屉里面,然后在上面贴上漂亮的标签,从此家里就一下子焕然一新。这样的小代码为什么不放进标准库里面呢?
这就是代码的美感。一种能够建立一个接口,把因为历史原因而产生的复杂性屏蔽起来,从而在自己的世界变得一切都井井有条,shipshape 。
这段代码函数的顺序也很有讲究,就在这几行里面,前面定义着,后面立马就是用起来:
const is = {
arr: a => Array.isArray(a),
obj: a => stringContains(Object.prototype.toString.call(a), 'Object'),
pth: a => is.obj(a) && a.hasOwnProperty('totalLength'),
svg: a => a instanceof SVGElement,
inp: a => a instanceof HTMLInputElement,
dom: a => a.nodeType || is.svg(a),
str: a => typeof a === 'string',
fnc: a => typeof a === 'function',
und: a => typeof a === 'undefined',
hex: a => /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a),
rgb: a => /^rgb/.test(a),
hsl: a => /^hsl/.test(a),
col: a => (is.hex(a) || is.rgb(a) || is.hsl(a)),
key: a => !defaultInstanceSettings.hasOwnProperty(a) && !defaultTweenSettings.hasOwnProperty(a) && a !== 'targets' && a !== 'keyframes'
}
pth( ) 基于 obj( ) 的判断来定义,dom( ) 用到了 svg( ),而 col( ) 用了前面的 hex( ),rgb( ),hsl( ) 。。。。这样子一步步渐进,每一步都清晰的在前面一步的基础上再走一步,这个过程就好像东野圭吾的小说里面的一个悬念上叠加一个悬念,直到把这一整段代码看完了,才知道整体的构思。
这一段代码是我在看 anime.js 的时候随手拿来的,因为相对比较完整,但更精彩的是在整个架构的设计和组合上面。
作者用了最少的代码量把互联网上散落各处的缓动函数(easing function)等等功能都统一化以后放在自己的小工具箱里面。看得我眼花缭乱,深感功力很深。
除了《如何判断一段程序是否优美?》提到的短以外,每个函数如果很短也是优美的体现。以 anime.js 为例,里面大多数的函数体都是三行语句以内,甚至最多的都是一行,直接返回,就如同题图的那段一样。就是这样的每个函数只加一点点功能,然后不断的组合,就完成了复杂的功能。这个和我们一直喜欢的乐高是概念,就是用最小的相同的小块,不断的重复的构建出任何想要构建的结构出来。
看代码如小说
看代码,就像看一部小说,有好的,有差的。不幸的是,除了文笔特别差的小说,很多小说需要花时间看完结局,才知道是不是真的好看。代码在这一点也很类似。虽然看一小段就知道个大概,但如果真的想评估的,还是需要耐着性子看下去,看到最后才能有更准确的判断。
如果有人把代码像小说一样进行推荐就好了,可以让除了计算机以外的人类,也可以享受阅读代码的乐趣。
为什么要读代码呢?阅读代码最大的好处是学习。别人的遣词造句的方法,组织段落的方法,甚至函数命名的方法,都是可以直接借鉴,用在自己的代码里面的。
熟读唐诗三百首,不会吟诗也会吟。代码届也是同样的道理。建议希望写出优美的代码的同学,应该没事儿读几段优秀的代码,绝对比写代码的时间更划算