原文链接:https://javascript.info/comments,translate with ❤️ by zhangbao.

从《代码结构》一章我们知道,注释分单行注释(以 // 开头)和多行注释(用 // 表示)。

我们通常使用它们来描述代码的工作方式和原因。

从第一眼看,注释应该是显而易见的,但在编程新手中的通常犯错。

坏的注释

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

  1. // This code will do this thing (...) and that thing (...)
  2. // ...and who knows what else...
  3. very;
  4. complex;
  5. code;

但是在良好的代码中,这种“解释性”注释的数量应该是最小的。说真的,如果没有它们,代码应该很容易理解。

关于这一点有一个很好的规则:“如果代码如此不清楚,它需要注释,那么也许它应该被重写”。

秘诀:分解函数

有时用一个函数替换代码是很有好处的,比如这里:

  1. function showPrimes(n) {
  2. nextPrime:
  3. for (let i = 2; i < n; i++) {
  4. // check if i is a prime number
  5. for (let j = 2; j < i; j++) {
  6. if (i % j == 0) continue nextPrime;
  7. }
  8. alert(i);
  9. }
  10. }

更好的变体,有一个分解函数 isPrime:

  1. function showPrimes(n) {
  2. for (let i = 2; i < n; i++) {
  3. if (!isPrime(i)) continue;
  4. alert(i);
  5. }
  6. }
  7. function isPrime(n) {
  8. for (let i = 2; i < n; i++) {
  9. if (n % i == 0) return false;
  10. }
  11. return true;
  12. }

现在我们可以很容易地理解代码了。函数本身变成了注释。这样的代码称为自描述

秘诀:创建函数

如果我们有一个像这样的长“代码表”:

  1. // 这里我们添加 whiskey
  2. for(let i = 0; i < 10; i++) {
  3. let drop = getWhiskey();
  4. smell(drop);
  5. add(drop, glass);
  6. }
  7. // 这里我们添加 juice
  8. for(let t = 0; t < 3; t++) {
  9. let tomato = getTomato();
  10. examine(tomato);
  11. let juice = press(tomato);
  12. add(juice, glass);
  13. }
  14. // ...

然后,将其重构为这样的函数可能是一个更好的变体:

  1. addWhiskey(glass);
  2. addJuice(glass);
  3. function addWhiskey(container) {
  4. for(let i = 0; i < 10; i++) {
  5. let drop = getWhiskey();
  6. //...
  7. }
  8. }
  9. function addJuice(container) {
  10. for(let t = 0; t < 3; t++) {
  11. let tomato = getTomato();
  12. //...
  13. }
  14. }

函数本身再一次告诉我们发生了什么。没有什么可注释的。拆分时代码结构也更好,很清楚每个功能的功能,需要的功能和返回的功能。

实际上,我们不能完全避免“解释性”数值。存在复杂的算法,为了优化,或者一些智能的“调整”。 但一般来说,我们应该尽量保持代码简单和自我描述。

好的注释

所以,解释性的评论通常是不好的。哪些评论是好的?

描述了体系结构

提供组件的高级概述,它们如何交互,在各种情况下控制流程是什么……简而言之 - 鸟瞰代码。 对于高级架构图,有一种特殊的图表语言 UML,绝对值得研究。

记录一个函数用法

有一个特殊的语法 JSDoc 来记录一个函数:用法,参数,返回值。

例如:

  1. /**
  2. * 返回 x 求 n 次幂后的结果.
  3. *
  4. * @param {number} x 求幂的底数.
  5. * @param {number} n 次幂,是一个自然数.
  6. * @return {number} x 求 n 次幂后的结果.
  7. */
  8. function pow(x, n) {
  9. ...
  10. }

这样的注释使我们能够理解这个函数的目的,并且在不查看代码的情况下正确地使用它。

顺便说一下,许多像 WebStorm 这样的编辑器也能理解它们,并使用它们来提供自动完成和一些自动的代码检查。

此外,还有一些工具,如 JSDoc 3,可以从评论中生成 html 文档。您可以在 http://usejsdoc.org/ 上阅读关于 JSDoc 的更多信息。

为什么这个任务是这样解决的?

写的内容很重要。 但是,对于理解正在发生的事情,未写的内容可能更为重要。 为什么这个任务完全解决了? 代码没有回答。

如果有很多方法可以解决这个问题,那么为什么呢? 特别是当它不是最明显的时候。

如果没有这些注释,以下情况是可能的:

  1. 您(或您的同事)打开了一段时间以前编写的代码,并发现它是“不是最佳的”。

  2. 你会想:“那时我是多么的愚蠢,我现在有多聪明”,然后用“更明显、更正确”的变体重写。

  3. 重写的冲动是好的。但在这个过程中,你会发现“更明显”的解决方案实际上是缺乏的。你甚至模糊地记得为什么,因为你很久以前就已经试过了。你恢复到正确的变体,但是时间被浪费了。

解释解决方案的注释是非常重要的。它们有助于以正确的方式继续发展。

代码的任何细微特征?它们在哪里被使用?

如果代码有任何微妙和反直觉的东西,那么它绝对值得注释。

总结

一个好的开发者的一个重要标志是注释:他们的存在,甚至他们的缺席。

良好的注释使我们能够很好地维护代码,在延迟后再回到它并更有效地使用它。

像这样注释:

  • 整体架构,高级视图。

  • 函数功能。

  • 重要的解决方案,特别是在不明显的情况下。

避免这样的注释:

  • 这说明了“代码是如何工作的”和“它是怎么做的”。

  • 只有在不可能使代码如此简单和自描述的情况下,才把它们放在一起,这样就不需要这些代码了。

注释也用于像 JSDoc3 这样的自动记录工具:他们读取并生成 HTML 文档(或以另一种格式的文档)。

(完)