# 代码质量

# 代码风格

我们的代码必须尽可能的清晰和易读。

这实际上是一种编程艺术 —— 以一种正确并且人们易读的方式编码来完成一个复杂的任务。一个良好的代码风格大大有助于实现这一点。

没有什么规则是“必须”的

没有什么规则是“刻在石头上”的。这些是风格偏好,而不是宗教教条。

# 风格指南

风格指南包含了“如何编写”代码的通用规则,例如:使用哪个引号、用多少空格来缩进、一行代码最大长度等非常多的细节。

当团队中的所有成员都使用相同的风格指南时,代码看起来将是统一的。无论是团队中谁写的,都是一样的风格。

当然,一个团队可以制定他们自己的风格指南,但是没必要这样做。现在已经有了很多制定好的代码风格指南可供选择。

下面列出一些受欢迎的选择:

  • Google JavaScript 风格指南
  • Airbnb JavaScript 风格指南
  • Idiomatic.JS
  • StandardJS

# 自动检查器

检查器(Linters)是可以自动检查代码样式,并提出改进建议的工具。

它们的妙处在于进行代码风格检查时,还可以发现一些代码错误,例如变量或函数名中的错别字。因此,即使你不想坚持某一种特定的代码风格,我也建议你安装一个检查器。

大多数检查器都可以与编辑器集成在一起:只需在编辑器中启用插件并配置代码风格即可。

例如,要使用 ESLint 你应该这样做:

  • 安装 Node.JS。
  • 使用 npm install -g eslint 命令(npm 是一个 JavaScript 包安装工具)安装 ESLint。
  • 在你的 JavaScript 项目的根目录(包含该项目的所有文件的那个文件夹)创建一个名为 .eslintrc 的配置文件。
  • 在集成了 ESLint 的编辑器中安装/启用插件。大多数编辑器都有这个选项。

下面是一个 .eslintrc 文件的例子:


{
  "extends": "eslint:recommended",
  "env": {
    "browser": true,
    "node": true,
    "es6": true
  },
  "rules": {
    "no-console": 0,
    "indent": 2
  }
}

这里的 "extends" 指令表示我们是基于 “eslint:recommended” 的设置项而进行设置的。之后,我们制定我们自己的规则。

# 糟糕的注释

新手倾向于使用注释来解释“代码中发生了什么”。就像这样

// 这里的代码会先做这件事(……)然后做那件事(……)
// ……谁知道还有什么……

但在好的代码中,这种“解释性”注释的数量应该是最少的。严格地说,就算没有它们,代码也应该很容易理解。

关于这一点有一个很棒的原则:“如果代码不够清晰以至于需要一个注释,那么或许它应该被重写。”

TIP

如果代码不够清晰以至于需要一个注释,那么或许它应该被重写。

# 好的注释

解释性注释通常来说都是不好的。那么哪一种注释才是好的呢?

  1. 描述架构

对组件进行高层次的整体概括,它们如何相互作用、各种情况下的控制流程是什么样的……简而言之 —— 代码的鸟瞰图。 不过这种高层次的东西还是专门写个文档来记录把还可以用上画图工具,比如 UML。

  1. 记录函数的参数和用法

有一个专门用于记录函数的语法 JSDoc:用法、参数和返回值。

/**
 * 返回 x 的 n 次幂的值。
 *
 * @param {number} x 要改变的值。
 * @param {number} n 幂数,必须是一个自然数。
 * @return {number} x 的 n 次幂的值。
 */
function pow(x, n) {
  ...
}
  1. 为什么任务以这种方式解决?

写了什么代码很重要。但是为什么 不 那样写可能对于理解正在发生什么更重要。

如果有很多种方法都可以解决这个问题,为什么偏偏是这一种?尤其当它不是最显而易见的那一种的时候。

  1. 代码有哪些巧妙的特性?它们被用在了什么地方?

如果代码存在任何巧妙和不显而易见的方法,那绝对需要注释。

// task4 依赖于前面三个的结果,但前面三个任务之间没有依赖关系
Promise.all([task1, task2, task3]).then((res) => {
  task4();
});

# 注释总结

一个好的开发者的标志之一就是他的注释:它们的存在甚至它们的缺席(译注:在该注释的地方注释,在不需要注释的地方则不注释,甚至写得好的自描述函数本身就是一种注释)。

好的注释可以使我们更好地维护代码,一段时间之后依然可以更高效地回到代码高效开发。

注释这些内容:

  • 整体架构,高层次的观点。
  • 函数的用法。
  • 重要的解决方案,特别是在不是很明显时。

避免注释:

  • 描述“代码如何工作”和“代码做了什么”。
  • 避免在代码已经足够简单或代码有很好的自描述性而不需要注释的情况下,还写些没必要的注释。

# 自动化测试

自动化测试将被用于进一步的任务中,并且还将被广泛应用在实际项目中。

常用测试工具套件

  • Mocha —— 核心框架:提供了包括通用型测试函数 describe 和 it,以及用于运行测试的主函数。
  • Chai —— 提供很多断言(assertion)支持的库。它提供了很多不同的断言,现在我们只需要用 assert.equal。
  • Sinon —— 用于监视函数、模拟内置函数和其他函数的库,我们在后面才会用到它。

# Babel

当我们使用语言的一些现代特性时,一些引擎可能无法支持这样的代码。正如上所述,并不是所有功能在任何地方都有实现。

这就是 Babel 来拯救的东西。

Babel 是一个 transpiler。它将现代的 JavaScript 代码转化为以前的标准形式。

实际上,Babel 包含了两部分:

第一,用于重写代码的 transpiler 程序。开发者在自己的电脑上运行它。它以之前的语言标准对代码进行重写。然后将代码传到面向用户的网站。 第二,polyfill。新的语言特性可能不仅包括语法结构,还包括新的内建函数。 Transpiler 会重写代码,将语法结构转换为旧的结构。但是对于新的内建函数,需要我们去实现。更新/添加新函数的脚本称为 “polyfill”。它“填补”了缺口,并添加了缺少的实现。

# 严格模式

除了正常的运行模式,JavaScript 还有第二种运行模式:严格模式(strict mode)。顾名思义,这种模式采用更加严格的 JavaScript 语法。

​ 早期的 JavaScript 语言有很多设计不合理的地方,但是为了兼容以前的代码,又不能改变老的语法,只能不断添加新的语法,引导程序员使用新语法。 严格模式是从 ES5 进入标准的, 严格模式体现了 JavaScript 更合理、更安全、更严谨的发展方向。

进入严格模式的标志,是一行字符串use strict

  • use strict放在脚本文件的第一行,整个脚本都将以严格模式运行。
  • use strict放在函数体的第一行,则整个函数以严格模式运行。

严格模式使得 JavaScript 的语法变得更严格,更多的操作会显式报错。其中有些操作,在正常模式下只会默默地失败,不会报错。

  1. 只读属性不可写
  2. 只设置了取值器的属性不可写
  3. 禁止扩展的对象不可扩展
  4. eval、arguments 不可用作标识名
  5. 函数不能有重名的参数
  6. 禁止八进制的前缀 0 表示法

严格模式增强了安全保护,从语法上防止了一些不小心会出现的错误。

  1. 全局变量必须显式声明
  2. 禁止 this 关键字指向全局对象
  3. 禁止使用 fn.callee、fn.caller
  4. 禁止使用 arguments.callee、arguments.caller
  5. 禁止删除变量
  6. 禁止使用 with 语句
  7. 创设 eval 作用域
  8. arguments 不在追踪参数的变化
  9. 非函数代码块不得声明函数
  10. 保留字