JavaScript 注释
在 JavaScript 开发中,注释不仅是记录代码逻辑的手段,更是团队协作的重要沟通工具。
高质量的注释能显著降低维护成本,帮助开发者快速理解复杂的业务逻辑或特殊的边界处理。
1. 语法维度的注释(三种形式)
每种注释都有其明确的“使用场景”:
1.1 单行注释 (//)
- 适用场景:对单行逻辑的补充说明、变量定义的含义说明。
- 特点:简洁快速。
- 技巧:建议在
//之后留一个空格,符合大多数代码风格规范(如 Airbnb/Google 规范)。
示例:
// 单行注释:解释非直观的逻辑或边界情况
const scrollOffset = element.getBoundingClientRect().top + window.scrollY - 80; // 减去 80px 是为了避开顶部固定导航栏
1.2 多行注释 (/* ... */)
- 适用场景:逻辑块的背景说明、版权声明、或者(在调试阶段)临时屏蔽某块逻辑。
- 注意:不要用多行注释来包裹“已失效代码”,这会导致代码库混乱。建议使用 Git 进行代码版本管理。
示例:
/*
* 此处进行轮询请求处理:
* 1. 检查当前网络状态
* 2. 如果网络正常,每隔 5s 发送心跳包
* 3. 如果达到最大重试次数,则中断请求
*/
function startPolling() {
// ... 代码逻辑
}1.3 文档注释 (/** ... */) - 即 JSDoc
- 适用场景:定义函数、类、模块接口的 API 文档。
- 强大之处:它是代码与 IDE 之间的桥梁。通过
@param、@returns等标签,IDE 能够准确识别数据类型并给予补全提示,这对于团队协作至关重要。
示例:
/**
* 根据用户 ID 获取其权限列表
* @param {string|number} userId - 用户的唯一标识符
* @param {boolean} [includeExpired=false] - 是否包含已过期权限 (可选参数)
* @returns {Promise<string[]>} 返回权限名称数组
* @throws {Error} 当用户不存在时抛出异常
*/
async function getUserPermissions(userId, includeExpired = false) {
// 实现逻辑...
}2. 工程化标记 (Tags)
在多人协作的大型项目中,单纯的文字说明是不够的,我们需要统一的“状态标记”来告诉队友代码的健康程度
| 标记 | 含义 | 建议 |
|---|---|---|
| TODO | 任务未完成 | 务必加上 [姓名] 和 [日期],方便追踪。 |
| FIXME | 代码有 Bug,但暂时绕过了 | 必须注明重构计划,避免产生技术债。 |
| HACK | 使用了非标准的“黑科技” | 说明为什么要用这种不优雅的手段(如兼容性修复)。 |
| NOTE | 补充说明 | 记录特定的业务规则或边缘案例。 |
| DEPRECATED | 方法即将弃用 | 告知开发者未来应使用哪个替代方案。 |
在实际项目中,这些标记可以直接在代码中充当“备忘录”。
示例:
// TODO: 孙悟空 - 2023-10-27 - 这里的 API 响应数据结构不稳定,后续需要增加 Schema 校验
const data = await fetchUserData();
// FIXME: 这里的循环在数据量超过 1 万条时会导致页面卡顿,需要优化为分页查询
for (let i = 0; i < largeArray.length; i++) {
processItem(largeArray[i]);
}
// HACK: 由于旧版 iOS Safari 的 Flexbox 渲染 Bug,此处增加一个额外的 1px padding
const containerStyle = { padding: '1px' }; 3. 最佳实践对比
3.1 过度注释/废话
// 将 a 和 b 相加并赋值给 c
let c = a + b;
// 循环 i 从 0 到 length
for (let i = 0; i < length; i++) {
console.log(i);
}这些注释完全是代码的“翻译”,不仅占空间,还会随着代码变动变得难以维护。
3.2 优秀的注释(解释决策动机)
// 为了提升性能,此处手动触发了内存回收,避免在大规模图像渲染时出现卡顿
if (window.gc) {
window.gc();
}
// 由于第三方 SDK 只支持同步回调,这里通过 setTimeout 将任务挂载到宏任务队列,以避免阻塞主线程 UI
setTimeout(() => {
thirdPartySDK.init();
}, 0);这些注释解释了为什么要这样做,即使代码本身很简单,但通过注释,维护者能够理解其深层的设计考虑。