前端注释规范
编写代码注释的最佳实践
好的注释可以提高代码的可读性和可维护性,从而提高代码质量。
作为研发同学,对于代码“注释”其实并不陌生。它往往作为我们代码文档的特殊补充而存在。
提倡加注释,但不能滥用。我们开发流程中会有Code Review过程,这样每个人都将了解好的注释是什么样的,同时你遇到不好的代码注释,也需要告诉他如何改进。
这里有一些规则可以帮助我们把注释写的更好。
规则 1:注释不应与代码重复。
规则 2:好的注释不能成为不清晰代码的借口。
规则3:如果不能写清楚的注释,可能是代码有问题。
规则 4:评论应该消除混乱,而不是引起混乱。
规则 5:在注释中解释单一的代码。
规则 6:提供复制代码的原始来源的链接。
规则 7:在最有帮助的地方包含指向外部参考的链接。
规则 8:修复错误时添加注释。
规则 9:使用注释来标记不完整的实现。
规则 1:注释不应与代码重复。注释不应重复代码的工作。应该去解释代码的模型和心智模型的映射关系,应说明为什么要使用这个代码模型,下面的例子就是反面教材:
// bad
/** the name. */
let name:string;
/** the version. */
let Version:string;
/** the info. */
let info:string;
// 使用给定的深度,在给定的子树中查找具有给定名称的节点。
func FindNodeInSubtree(subTree *Node, name string, depth *int) *Node {
}
规则 2:好的注释不能成为不清晰代码的借口。如起变量名时候取其实际含义,没必要随便写个变量名然后在注释里面偷偷用功。起函数名时动词+名词结合。我们应当追求「代码自注释」,即代码本身就拥有较高的可读性(通过清晰的命名、合理的结构等)。 别害怕长名称,长而具有描述性的名称,比长注释好。别害怕花时间取名字。
//bad
// 如果已经准备好数据,就渲染表格
if (data.success && data.result.length > 0) {
renderTable(data);
}
//good
const isTableDataReady = data.success && data.result.length > 0;
if (isTableDataReady) {
renderTable(data);
}
//good
init: function() {
// 获取配置信息
const config = getConfig();
// 获取用户信息
const userInfo = getUserInfo();
// 根据配置和用户信息,进行初始化
doInit(config, userInfo);
// 如果存在自定义配置时的特殊逻辑
if (config.custom) {
...
}
}
规则 3:如果不能写清楚的注释,可能是代码有问题
**克尼根定律:布莱恩·克尼根正是与人合著了《C编程语言圣经》的人,以这条有见地的定律而闻名。关键在于:写好代码,写可读代码,写简单代码,只要不是聪明的代码就行。
试图用象牙塔的复杂性来锻炼你的编程能力,与编写干净、更好的代码的意义恰恰相反。你的代码越难理解,当它不可避免地崩溃时,调试就越困难。
规则 4:注释应该消除混乱,而不是引起混乱。若编程语言足够有表现力,我们就不需要注释。代码在演化,注释却不总是随之变动。不准确的注释比没注释坏的多。写为什么做,少写做了什么。
``
规则 5:在注释中解释单一的代码
//bad,代码中不应该去解释大家都能理解的代码,除非是在给新手编写教程。
final Object value = (new JSONTokener(jsonString)).nextValue();
// Note that JSONTokener.nextValue() may return
// a value equals() to null.
if (value == null || value.equals(null)) {
return null;
}
规则 6:提供复制代码的原始来源的链接
/** 将可绘制对象转换为位图. via https://stackoverflow.com/a/46018816/2219998. */
return (int) (0.3 * red + 0.59 * green + 0.11 * blue);
规则 7:在最有帮助的地方包含指向外部参考的链接
/**
* Returns the current location object, which represents the current URL in web
* browsers.
*
* Note: If you're using this it may mean you're doing some of your own
* "routing" in your app, and we'd like to know what your use case is. We may
* be able to provide something higher-level to better suit your needs.
*
* @see https://reactrouter.com/docs/en/v6/api#uselocation
*/
export declare function useLocation(): Location;
规则 9:使用注释来标记不完整的实现
即使代码中有已知的限制,有时还是有必要检查它。虽然不分享代码中已知的缺陷很有诱惑力,但最好将这些明确化,例如使用TODO注释:
// TODO(hal): We are making the decimal separator be a period,
// regardless of the locale of the phone. We need to think about
// how to allow comma as decimal separator, which will require
// updating number parsing and other places that transform numbers
// to strings, such as FormatAsDecimal
注释规约
【推荐】单行注释使用 //
注释应单独一行写在被注释对象的上方,不要追加在某条语句的后面:
// bad
const active = true; // is current tab
// good
// is current tab
const active = true;
注释行的上方需要有一个空行(除非注释行上方是一个块的顶部),以增加可读性:
// bad
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
注释行上面是一个块的顶部时不需要空行
// good
function getType() {
console.log('fetching type...');
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
// good
function getType() {
// set the default type to 'no type'
const type = this.type || 'no type';
return type;
}
【推荐】多行注释使用 /** ... */
,而不是多行的 //
// bad
// make() returns a new element
// based on the passed in tag name
function make(tag) {
// ...
return element;
}
// good
/**
* make() returns a new element
* based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
【强制】注释内容和注释符之间需要有一个空格,以增加可读性。eslint: spaced-comment
// bad
//is current tab
const active = true;
// good
// is current tab
const active = true;
// bad
/**
*make() returns a new element
*based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
// good
/**
* make() returns a new element
* based on the passed-in tag name
*/
function make(tag) {
// ...
return element;
}
【推荐】使用特殊注释标记。
有时我们发现某个可能的 bug,但因为一些原因还没法修复;或者某个地方还有一些待完成的功能,这时我们需要使用相应的特殊标记注释来告知未来的自己或合作者。常用的特殊标记有两种:
-
FIXME: 说明问题是什么
-
TODO: 说明还要做什么或者问题的解决方案
class Calculator extends Abacus {
constructor() {
super();
// FIXME: shouldn’t use a global here
total = 0;
// TODO: total should be configurable by an options param
this.total = 0;
}
}
【推荐】文档类注释,如函数、类、文件、事件等,使用 jsdoc 规范
@see 这是JsDoc规范 这是链接 JsDoc规范。
JSDoc 是一个根据 JavaScript 文件中注释信息,生成 JavaScript 应用程序或模块的API文档的工具。
/**
* Book类,代表一个书本.
* @constructor
* @param {string} title - 书本的标题.
* @param {string} author - 书本的作者.
*/
function Book(title, author) {
this.title=title;
this.author=author;
}
Book.prototype={
/**
* 获取书本的标题
* @returns {string|*}
*/
getTitle:function(){
return this.title;
},
/**
* 设置书本的页数
* @param pageNum {number} 页数
*/
setPageNum:function(pageNum){
this.pageNum=pageNum;
}
};
【推荐】工具使用。我们可以使用一些工具来保证注释质量,例如:
Eslint:保证一致的注释风格ESLint 是当下最流行的 JS 代码检查工具,ESLint 中有一些注释相关的规则,用户可选择开启:
@see 这是Eslint规范 这是链接 EsLint规范。
no-warning-comments
开发者经常给代码添加注释,标明哪些没有完成或需要审查。在你认为代码可以发布之前,你很有可能想修复或审查代码,然后删除注释。capitalized-comments
如果您不关心代码库中注释的语法风格,则可以禁用此规则。控制注释如果是英文首字母必须大写line-comment-position
如果您不关心有不同的行注释样式,那么您可以关闭此规则。控制行注释位置lines-around-comment
许多人喜欢简洁的代码风格,并且不介意与代码冲突的评论。如果您属于该类别,则此规则不适合您。 控制间隔评论,块前空间。multiline-comment-style
如果您不想为多行注释强制执行特定样式,则可以禁用该规则。 控制多行注释样式。no-inline-comments
控制内联注释位置。spaced-comment
控制一些注释间隔。
结论
我希望上面的例子已经表明注释不能原谅或修复错误的代码;它们通过提供不同类型的信息来补充好的代码。
正如 Stack Overflow 联合创始人 Jeff Atwood 所写的那样,“代码告诉你如何,评论告诉你为什么。”
遵循这些规则应该可以节省您和您的队友的时间和挫败感。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通