JavaScript 编码风格
介绍
作者根据 Robert C. Martin 《代码整洁之道》总结了适用于 JavaScript 的软件工程原则《Clean Code JavaScript》。
本文是对其的翻译。
不必严格遵守本文的所有原则,有时少遵守一些效果可能会更好,具体应根据实际情况决定。这是根据《代码整洁之道》作者多年经验整理的代码优化建议,但也仅仅只是一份建议。
软件工程已经发展了 50 多年,至今仍在不断前进。现在,把这些原则当作试金石,尝试将他们作为团队代码质量考核的标准之一吧。
最后你需要知道的是,这些东西不会让你立刻变成一个优秀的工程师,长期奉行他们也并不意味着你能够高枕无忧不再犯错。千里之行,始于足下。我们需要时常和同行们进行代码评审,不断优化自己的代码。不要惧怕改善代码质量所需付出的努力,加油。
变量
使用有意义,可读性好的变量名
反例:
正例:
使用 ES6 的 const 定义常量
反例中使用”var”定义的”常量”是可变的。
在声明一个常量时,该常量在整个程序中都应该是不可变的。
反例:
正例:
对功能类似的变量名采用统一的命名风格
反例:
正例:
使用易于检索名称
我们需要阅读的代码远比自己写的要多,使代码拥有良好的可读性且易于检索非常重要。阅读变量名晦涩难懂的代码对读者来说是一种相当糟糕的体验。
让你的变量名易于检索。
反例:
正例:
使用说明变量(即有意义的变量名)
反例:
正例:
不要绕太多的弯子
显式优于隐式。
反例:
正例:
避免重复的描述
当类/对象名已经有意义时,对其变量进行命名不需要再次重复。
反例:
正例:
避免无意义的条件判断
反例:
正例:
函数
函数参数 (理想情况下应不超过 2 个)
限制函数参数数量很有必要,这么做使得在测试函数时更加轻松。过多的参数将导致难以采用有效的测试用例对函数的各个参数进行测试。
应避免三个以上参数的函数。通常情况下,参数超过两个意味着函数功能过于复杂,这时需要重新优化你的函数。当确实需要多个参数时,大多情况下可以考虑这些参数封装成一个对象。
JS 定义对象非常方便,当需要多个参数时,可以使用一个对象进行替代。
反例:
正例:
函数功能的单一性
这是软件功能中最重要的原则之一。
功能不单一的函数将导致难以重构、测试和理解。功能单一的函数易于重构,并使代码更加干净。
反例:
正例:
函数名应明确表明其功能
反例:
正例:
函数应该只做一层抽象
当函数的需要的抽象多于一层时通常意味着函数功能过于复杂,需将其进行分解以提高其可重用性和可测试性。
反例:
正例:
移除重复的代码
永远、永远、永远不要在任何循环下有重复的代码。
这种做法毫无意义且潜在危险极大。重复的代码意味着逻辑变化时需要对不止一处进行修改。JS 弱类型的特点使得函数拥有更强的普适性。好好利用这一优点吧。
反例:
正例:
采用默认参数精简代码
反例:
正例:
使用 Object.assign 设置默认对象
反例:
正例:
不要使用标记(Flag)作为函数参数
这通常意味着函数的功能的单一性已经被破坏。此时应考虑对函数进行再次划分。
反例:
正例:
避免副作用
当函数产生了除了“接受一个值并返回一个结果”之外的行为时,称该函数产生了副作用。比如写文件、修改全局变量或将你的钱全转给了一个陌生人等。
程序在某些情况下确实需要副作用这一行为,如先前例子中的写文件。这时应该将这些功能集中在一起,不要用多个函数/类修改某个文件。用且只用一个 service 完成这一需求。
反例:
正例:
不要写全局函数
在 JS 中污染全局是一个非常不好的实践,这么做可能和其他库起冲突,且调用你的 API 的用户在实际环境中得到一个 exception 前对这一情况是一无所知的。
想象以下例子:如果你想扩展 JS 中的 Array,为其添加一个 diff
函数显示两个数组间的差异,此时应如何去做?你可以将 diff 写入 Array.prototype
,但这么做会和其他有类似需求的库造成冲突。如果另一个库对 diff 的需求为比较一个数组中首尾元素间的差异呢?
使用 ES6 中的 class 对全局的 Array 做简单的扩展显然是一个更棒的选择。
反例:
正例:
采用函数式编程
函数式的编程具有更干净且便于测试的特点。尽可能的使用这种风格吧。
反例:
正例:
封装判断条件
反例:
正例:
避免“否定情况”的判断
反例:
正例:
避免条件判断
这看起来似乎不太可能。
大多人听到这的第一反应是:“怎么可能不用 if 完成其他功能呢?”许多情况下通过使用多态(polymorphism)可以达到同样的目的。
第二个问题在于采用这种方式的原因是什么。答案是我们之前提到过的:保持函数功能的单一性。
反例:
正例:
避免类型判断(part 1)
JS 是弱类型语言,这意味着函数可接受任意类型的参数。
有时这会对你带来麻烦,你会对参数做一些类型判断。有许多方法可以避免这些情况。
反例:
正例:
避免类型判断(part 2)
如果需处理的数据为字符串,整型,数组等类型,无法使用多态并仍有必要对其进行类型检测时,可以考虑使用 TypeScript。
反例:
正例:
避免过度优化
现代的浏览器在运行时会对代码自动进行优化。有时人为对代码进行优化可能是在浪费时间。
反例:
正例:
删除无效的代码
不再被调用的代码应及时删除。
反例:
正例: