- 文档/教程
- 前端
【免费下载链接】en.javascript.info
Modern JavaScript Tutorial
本篇指南源自 Modern JavaScript Tutorial 项目「代码质量」章节中的《Comments》一文(见 1-js/03-code-quality/03-comments/article.md),系统讲解 JavaScript 代码注释的正确打开方式:哪些注释是新手常犯的错误、哪些注释值得保留、以及如何通过"抽出函数""自描述代码"等重构手法让代码本身替你说话。读完你将掌握一套可直接套用的注释取舍标准,并了解 JSDoc 等自动化文档工具的使用方法,让注释真正服务于代码维护,而不是成为噪音。
先打好语法地基:注释的两种基本形式
在讨论"该不该写注释"之前,先明确 JavaScript 注释的两种语法形式,它们早在「代码结构」章节就有过完整介绍(见 1-js/02-first-steps/02-structure/article.md#L93-L153):
- 单行注释:以两个正斜杠
//开头,行尾结束。可以独占一行,也可以跟在一条语句之后:
// This comment occupies a line of its own alert('Hello'); alert('World'); // This comment follows the statement- 多行注释:以
/*开头、*/结尾,可以跨越多行:
/* An example with two messages. This is a multiline comment. */ alert('Hello'); alert('World');关于注释语法,有两点容易被新手忽略的事实:
- 注释内容完全被引擎忽略。把代码放进
/* ... */中就不会执行,因此多行注释常被用来临时"注释掉"一段代码以禁用功能:
/* Commenting out the code alert('Hello'); */ alert('World');嵌套注释不受支持。
/*...*/内部不能再出现另一层/*...*/,否则代码会直接报错——这一点与 CSS 等语言不同,务必留意。注释不影响生产环境性能。虽然注释会增大代码体积,但发布到生产服务器前通常会有压缩(minify)工具自动剥离注释,因此大胆写注释不会有任何负面开销。
关于快捷键:在大多数编辑器中,Ctrl+/(Mac 为Cmd+/)可注释/取消注释单行,选中代码块后按下Ctrl+Shift+/(Mac 为Cmd+Option+/)可快速生成多行注释。
坏注释:解释"代码在做什么"
编程新手最常见的误区,就是用注释去描述代码的执行过程——"这段代码做了什么":
// This code will do this thing (...) and that thing (...) // ...and who knows what else... very; complex; code;在高质量代码中,这类"解释性注释"应当被压缩到最少。代码本身应当足够清晰,让人无需借助注释就能读懂。业内有一条非常经典的原则:
"如果一段代码晦涩到必须靠注释才能看懂,那正确的做法是重写它,而不是注释它。"
也就是说,解释性注释的存在往往不是注释的问题,而是代码设计的问题。与其用注释为糟糕的代码辩解,不如动手改善代码本身。下面给出教程中提出的两条具体重构配方。
配方一:抽出函数(factor out functions)
考虑下面的showPrimes:它的内层循环里用一段注释标出"检查 i 是否为素数":
function showPrimes(n) { nextPrime: for (let i = 2; i < n; i++) { // check if i is a prime number for (let j = 2; j < i; j++) { if (i % j == 0) continue nextPrime; } alert(i); } }更好的写法是把素数判断抽成独立的isPrime函数,让调用处的逻辑一目了然:
function showPrimes(n) { for (let i = 2; i < n; i++) { if (!isPrime(i)) continue; alert(i); } } function isPrime(n) { for (let i = 2; i < n; i++) { if (n % i == 0) return false; } return true; }重构之后,注释消失了,但代码反而更容易理解——函数本身就变成了注释。这类代码被称为自描述代码(self-descriptive):从函数名就能读出意图,无需逐行追踪实现细节。
配方二:把长代码片段改写为函数(create functions)
再看一个更长的例子:一段用注释分块的"流程清单":
// here we add whiskey for(let i = 0; i < 10; i++) { let drop = getWhiskey(); smell(drop); add(drop, glass); } // here we add juice for(let t = 0; t < 3; t++) { let tomato = getTomato(); examine(tomato); let juice = press(tomato); add(juice, glass); } // ...每块代码都需要一条"这里是干什么的"注释,恰恰说明代码本身缺少可读的结构。将其重构为语义清晰的函数后,主流程变成了一行行的"自白":
addWhiskey(glass); addJuice(glass); function addWhiskey(container) { for(let i = 0; i < 10; i++) { let drop = getWhiskey(); //... } } function addJuice(container) { for(let t = 0; t < 3; t++) { let tomato = getTomato(); //... } }同样的道理:函数名自己说明了一切,不再需要注释。而且拆分后代码结构更好——每个函数做什么、接收什么参数、返回什么结果,都清晰可辨。
无法完全避免解释性注释的例外
现实中我们不可能完全消灭解释性注释:总存在复杂的算法,也总有为优化而生的"聪明技巧"(tweaks),它们天然难以一眼读懂。但总的原则不变——尽可能让代码简单、自描述,把注释留给真正需要它的地方。
好注释:真正值得写的内容
既然"解释性注释"通常是坏的,那么哪些注释是有价值的?教程给出四类"好注释"。
1. 描述整体架构
注释应该提供代码的"上帝视角":组件的高层概览、它们之间如何交互、各种场景下的控制流是怎样的。这类架构级注释帮助后人快速建立全局认知。教程还特别提到UML(Unified Modeling Language,统一建模语言)——一种专门用于绘制高层架构图、解释代码结构的语言,值得花时间学习。
2. 文档化函数的参数与用法
用专门的 JSDoc 语法为函数编写文档:说明用法、参数、返回值。典型示例:
/** * Returns x raised to the n-th power. * * @param {number} x The number to raise. * @param {number} n The power, must be a natural number. * @return {number} x raised to the n-th power. */ function pow(x, n) { ... }这类注释让你不必翻看函数实现,就能理解它的用途并正确调用。JSDoc 的价值还体现在工具链上:
- 许多编辑器(如 JetBrains 的 WebStorm)能解析 JSDoc,在写代码时提供自动补全(autocomplete)和自动代码检查;
- 有专门的工具(如 JSDoc 3)可以读取 JSDoc 注释并自动生成 HTML 格式的文档。这意味着注释不只是一段说明文字,更是可编译的文档源材料。
补充:在教程「代码质量」章节的定位中,注释与测试、编码风格共同构成了代码可维护性的三块基石。如果说 JSDoc 是"函数级的文档",那么行为驱动开发(BDD)中的 spec 则是"行为级的文档"——详见 1-js/03-code-quality/05-testing-mocha/article.md#L23-L64,测试(tests)、文档(documentation)和示例(examples)三位一体,很多"代码该怎么用"的问题,用测试表达往往比用注释更可靠、更不易失真。
3. 解释"为什么用这种方式解决任务"
已经写出来的内容重要,没有写出来的内容可能更重要。代码本身回答不了"为什么":为什么这个任务偏偏要这样解决?当存在多种解法时,为什么选这一种,尤其是当它不是最直观的那一种时?
教程给出了一段非常典型的场景推演:你(或同事)隔了一段时间打开自己写的代码,觉得它"不够优雅"——"当时的我多么愚蠢,现在的我聪明多了"——于是用"更显然、更正确"的方案重写。结果写着写着发现,"更显然"的方案其实有缺陷,你甚至隐约记得原因,因为很久以前就试过这条路。最终你回退到正确的版本,但时间已经浪费掉了。
解释"为什么"的注释非常重要,它能帮助后人沿着正确的方向继续开发,避免重复踩坑、重复试错。
4. 标注代码中的微妙特性及其使用位置
如果代码中有任何**微妙(subtle)且反直觉(counter-intuitive)**的地方,绝对值得加注释。这类注释提醒读者"这里有个坑",防止后来者在不理解设计意图的情况下"顺手修复"而引入回归。
与教程其他章节的呼应:注释在代码质量体系中的位置
注释不是孤立的话题,它和教程「代码质量」章节的其他主题紧密咬合:
- 编码风格(Coding Style):自描述代码的前提是良好的命名、合理的缩进和克制的嵌套层级。教程在 1-js/03-code-quality/02-coding-style/article.md#L158-L224 中专门演示了如何用
continue、提前return等手段减少嵌套层级——代码结构越平坦,需要注释"打圆场"的地方就越少。 - 忍者代码(Ninja Code):
04-ninja-code章节以反讽口吻总结了所有"毁掉可读性"的技巧——单字母变量、极端缩写、过度抽象的命名、把代码压到最短(见 1-js/03-code-quality/04-ninja-code/article.md)。那些"需要注释才能解释的复杂代码",往往正是这些反模式积累的结果。读者不妨把本篇文章与忍者代码对照阅读:前者告诉你注释该怎么写,后者告诉你什么代码会逼着人写注释。 - 自动化测试(Mocha/BDD):如前面所述,函数的"使用说明"完全可以用可执行的测试来表达,测试即文档(详见 1-js/03-code-quality/05-testing-mocha/article.md)。
总结:注释取舍清单
一位优秀开发者的重要标志,恰恰体现在注释上——包括注释的"存在"与"缺席"。好的注释让你能长期维护代码、隔一段时间回来仍能快速上手、并更有效地使用它。
应该注释的内容:
- 整体架构、高层视角;
- 函数的用法(参数、返回值);
- 重要的解法,尤其是当它并非一眼可见时;
- 代码中微妙、反直觉的细节及其使用位置。
应该避免的注释:
- 描述"代码如何工作"和"代码做了什么"的解释性注释;
- 只有在无法把代码写得足够简单、自描述时,才允许出现这类注释。
善用自动化文档工具:注释还可以被 JSDoc 这类自动文档工具读取,用于生成 HTML 或其他格式的文档——把注释从"给人看的话"升级为"可编译的文档资产"。
最后记住这句话:好的代码自带注释,坏的代码才需要注释来辩护。当你想写"这段代码在做什么"的时候,先想想——它能不能被重构得更自描述?
- 文档/教程
- 前端
【免费下载链接】en.javascript.info
Modern JavaScript Tutorial
相关推荐
NSwag代码生成代码模板注释:模板内注释最佳实践
NSwag代码生成代码模板注释:模板内注释最佳实践 NSwag是一个强大的OpenAPI/Swagger代码生成工具,能够自动生成客户端代码和API文档。在NS
开发工具代码生成API设计3分钟掌握Headlamp:让Kubernetes资源监控变得如此简单
3分钟掌握Headlamp:让Kubernetes资源监控变得如此简单 你是否曾经面对复杂的Kubernetes集群感到手足无措?资源使用情况不明、性能瓶颈难寻
云原生开发工具如何快速上手FinMem:面向AI交易新手的完整入门指南
如何快速上手FinMem:面向AI交易新手的完整入门指南 FinMem是一款基于大型语言模型(LLM)的高性能交易代理框架,它融合了分层记忆和角色设计,能帮助A
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考