JSDoc 最佳实践 #
文档编写原则 #
清晰简洁 #
javascript
// ✅ 好的做法:清晰简洁
/**
* 计算两个数字的和
* @param {number} a - 第一个数字
* @param {number} b - 第二个数字
* @returns {number} 两数之和
*/
function add(a, b) {
return a + b;
}
// ❌ 不好的做法:过于冗长
/**
* 这个函数用于计算两个数字的和。
* 它接受两个数字作为参数,然后返回这两个数字相加的结果。
* 第一个参数是一个数字,第二个参数也是一个数字。
* 返回值是一个数字,表示两个输入数字的和。
*
* @param {number} a - 这是一个数字类型的参数,表示第一个要相加的数字
* @param {number} b - 这是一个数字类型的参数,表示第二个要相加的数字
* @returns {number} 返回一个数字,表示两个输入数字相加的结果
*/
function add(a, b) {
return a + b;
}
保持同步 #
javascript
// ✅ 好的做法:文档与代码同步
/**
* 创建用户
* @param {string} name - 用户名
* @param {string} email - 邮箱地址
* @param {number} [age] - 年龄(可选)
* @returns {User} 用户实例
*/
function createUser(name, email, age) {
return new User(name, email, age);
}
// ❌ 不好的做法:文档与代码不同步
/**
* 创建用户
* @param {string} name - 用户名
* @param {string} email - 邮箱地址
*/
function createUser(name, email, age, phone) {
return new User(name, email, age, phone);
}
使用具体类型 #
javascript
// ✅ 好的做法:使用具体类型
/**
* @param {string[]} names - 名称数组
* @param {Object<string, number>} scores - 分数映射
* @returns {Promise<User[]>} 用户列表 Promise
*/
// ❌ 不好的做法:使用模糊类型
/**
* @param {Array} names - 数组
* @param {Object} scores - 对象
* @returns {Promise} Promise
*/
函数文档规范 #
基本函数 #
javascript
/**
* 格式化日期为指定格式的字符串
*
* @param {Date} date - 要格式化的日期对象
* @param {string} [format='YYYY-MM-DD'] - 格式字符串
* @returns {string} 格式化后的日期字符串
*
* @example
* formatDate(new Date())
* // 返回 '2024-01-15'
*
* @example
* formatDate(new Date(), 'YYYY/MM/DD')
* // 返回 '2024/01/15'
*/
function formatDate(date, format = 'YYYY-MM-DD') {
// ...
}
复杂参数 #
javascript
/**
* 发送 HTTP 请求
*
* @param {string} url - 请求地址
* @param {Object} [options] - 请求选项
* @param {string} [options.method='GET'] - 请求方法
* @param {Object} [options.headers] - 请求头
* @param {Object|string} [options.body] - 请求体
* @param {number} [options.timeout=5000] - 超时时间(毫秒)
* @param {boolean} [options.withCredentials=false] - 是否携带凭证
* @returns {Promise<Response>} 响应 Promise
*
* @throws {NetworkError} 网络错误时抛出
* @throws {TimeoutError} 请求超时时抛出
*
* @example
* // GET 请求
* const data = await request('/api/users')
*
* @example
* // POST 请求
* const result = await request('/api/users', {
* method: 'POST',
* body: { name: 'John' }
* })
*/
async function request(url, options = {}) {
// ...
}
回调函数 #
javascript
/**
* 异步处理数据
*
* @param {Array} items - 数据项数组
* @param {Function} iterator - 处理函数
* @param {*} iterator.item - 当前项
* @param {number} iterator.index - 当前索引
* @param {Function} iterator.callback - 完成回调
* @param {Function} [callback] - 完成回调
*
* @example
* processItems(items, (item, index, cb) => {
* // 处理 item
* cb(null, result)
* }, (err, results) => {
* // 所有项处理完成
* })
*/
function processItems(items, iterator, callback) {
// ...
}
类文档规范 #
类定义 #
javascript
/**
* 用户管理类
*
* 提供用户的增删改查功能。
*
* @class
* @example
* const manager = new UserManager()
* const user = await manager.create({ name: 'John' })
*/
class UserManager {
/**
* 创建 UserManager 实例
*
* @param {Object} [config] - 配置选项
* @param {string} [config.apiBase='/api'] - API 基础地址
* @param {number} [config.timeout=5000] - 请求超时时间
*/
constructor(config = {}) {
/**
* API 基础地址
* @type {string}
* @readonly
*/
this.apiBase = config.apiBase || '/api';
/**
* 请求超时时间
* @type {number}
*/
this.timeout = config.timeout || 5000;
/**
* 用户缓存
* @private
* @type {Map<number, User>}
*/
this._cache = new Map();
}
/**
* 创建用户
*
* @param {Object} data - 用户数据
* @param {string} data.name - 用户名
* @param {string} data.email - 邮箱地址
* @returns {Promise<User>} 用户实例
*
* @fires UserManager#create
* @throws {ValidationError} 数据验证失败时抛出
*
* @example
* const user = await manager.create({
* name: 'John',
* email: 'john@example.com'
* })
*/
async create(data) {
// ...
}
/**
* 获取默认配置
*
* @static
* @returns {Object} 默认配置对象
*/
static getDefaultConfig() {
return {
apiBase: '/api',
timeout: 5000
};
}
}
继承类 #
javascript
/**
* 管理员用户类
*
* @class Admin
* @extends User
* @example
* const admin = new Admin('John', ['read', 'write'])
*/
class Admin extends User {
/**
* 创建管理员实例
*
* @param {string} name - 用户名
* @param {string[]} permissions - 权限列表
*/
constructor(name, permissions) {
super(name);
/**
* 权限列表
* @type {string[]}
*/
this.permissions = permissions;
}
/**
* 检查是否有指定权限
*
* @param {string} permission - 权限名称
* @returns {boolean} 是否有权限
*
* @example
* admin.hasPermission('read') // true
*/
hasPermission(permission) {
return this.permissions.includes(permission);
}
}
模块文档规范 #
模块定义 #
javascript
/**
* HTTP 请求工具模块
*
* 提供统一的 HTTP 请求处理功能。
*
* @module utils/http
* @example
* import { get, post } from 'utils/http'
*
* const data = await get('/api/users')
* const result = await post('/api/users', { name: 'John' })
*/
/**
* 发送 GET 请求
*
* @param {string} url - 请求地址
* @param {Object} [options] - 请求选项
* @returns {Promise<*>} 响应数据 Promise
*/
export async function get(url, options) {
// ...
}
/**
* 发送 POST 请求
*
* @param {string} url - 请求地址
* @param {Object} data - 请求数据
* @param {Object} [options] - 请求选项
* @returns {Promise<*>} 响应数据 Promise
*/
export async function post(url, data, options) {
// ...
}
/**
* 默认请求配置
*
* @constant {Object}
*/
export const defaultConfig = {
timeout: 5000,
headers: {
'Content-Type': 'application/json'
}
};
类型导出 #
javascript
/**
* 类型定义模块
*
* @module types
*/
/**
* 用户类型
* @typedef {Object} User
* @property {number} id - 用户 ID
* @property {string} name - 用户名
* @property {string} email - 邮箱地址
*/
/**
* API 响应类型
* @template T
* @typedef {Object} ApiResponse
* @property {number} code - 状态码
* @property {string} message - 消息
* @property {T} [data] - 数据
*/
export { User, ApiResponse };
类型定义规范 #
使用 typedef #
javascript
/**
* 用户类型
*
* @typedef {Object} User
* @property {number} id - 用户 ID
* @property {string} name - 用户名
* @property {string} email - 邮箱地址
* @property {string[]} [roles] - 角色列表
* @property {Date} [createdAt] - 创建时间
*/
/**
* 创建用户
*
* @param {User} user - 用户对象
* @returns {Promise<User>}
*/
async function createUser(user) {
// ...
}
复用类型定义 #
javascript
// types.js
/**
* @typedef {Object} BaseEntity
* @property {number} id - 实体 ID
* @property {Date} createdAt - 创建时间
* @property {Date} updatedAt - 更新时间
*/
/**
* @typedef {BaseEntity & {
* name: string,
* email: string
* }} User
*/
// user.js
/**
* @typedef {import('./types').User} User
*/
/**
* @param {User} user
*/
function processUser(user) {
// ...
}
泛型类型 #
javascript
/**
* 分页结果类型
*
* @template T
* @typedef {Object} PaginatedResult
* @property {T[]} items - 数据项
* @property {number} total - 总数
* @property {number} page - 当前页
* @property {number} pageSize - 每页数量
*/
/**
* 获取用户列表
*
* @param {number} [page=1] - 页码
* @param {number} [pageSize=10] - 每页数量
* @returns {Promise<PaginatedResult<User>>}
*/
async function getUsers(page = 1, pageSize = 10) {
// ...
}
示例编写规范 #
基本示例 #
javascript
/**
* 计算两数之和
*
* @param {number} a - 第一个数字
* @param {number} b - 第二个数字
* @returns {number} 两数之和
*
* @example
* add(1, 2) // 返回 3
*/
function add(a, b) {
return a + b;
}
多场景示例 #
javascript
/**
* 格式化字符串
*
* @param {string} template - 模板字符串
* @param {Object} data - 数据对象
* @returns {string} 格式化后的字符串
*
* @example <caption>基本用法</caption>
* format('Hello, {name}!', { name: 'John' })
* // 返回 'Hello, John!'
*
* @example <caption>多个占位符</caption>
* format('{greeting}, {name}!', { greeting: 'Hi', name: 'Jane' })
* // 返回 'Hi, Jane!'
*
* @example <caption>嵌套对象</caption>
* format('City: {address.city}', { address: { city: 'Beijing' } })
* // 返回 'City: Beijing'
*/
function format(template, data) {
// ...
}
异步示例 #
javascript
/**
* 获取用户信息
*
* @param {number} id - 用户 ID
* @returns {Promise<User>} 用户 Promise
*
* @example
* // 使用 async/await
* async function main() {
* const user = await getUser(1)
* console.log(user.name)
* }
*
* @example
* // 使用 Promise.then
* getUser(1).then(user => {
* console.log(user.name)
* })
*/
async function getUser(id) {
// ...
}
团队协作规范 #
文档风格指南 #
javascript
// docs/STYLE_GUIDE.md
## JSDoc 文档风格指南
### 1. 注释格式
- 使用 `/** */` 格式
- 每行以 `*` 开头
- 标签前后各空一行
### 2. 描述规范
- 第一行是简短描述(不超过一行)
- 详细描述另起一段
- 使用中文描述
### 3. 类型规范
- 使用具体类型,避免 `*` 或 `any`
- 数组使用 `Type[]` 格式
- 对象使用 `@typedef` 定义
### 4. 参数规范
- 所有参数必须有描述
- 可选参数使用 `[param]` 格式
- 默认值使用 `=value` 格式
### 5. 示例规范
- 每个公共 API 至少有一个示例
- 示例要简洁明了
- 包含预期输出
代码审查检查清单 #
markdown
## JSDoc 代码审查检查清单
- [ ] 所有公共 API 都有文档
- [ ] 参数类型正确
- [ ] 返回值类型正确
- [ ] 描述清晰准确
- [ ] 示例可以运行
- [ ] 文档与代码同步
- [ ] 使用了正确的标签
- [ ] 类型定义完整
ESLint 集成 #
javascript
// .eslintrc.js
module.exports = {
rules: {
// 要求 JSDoc 注释
'require-jsdoc': ['error', {
require: {
FunctionDeclaration: true,
MethodDefinition: true,
ClassDeclaration: true,
ArrowFunctionExpression: false
}
}],
// 验证 JSDoc 格式
'valid-jsdoc': ['error', {
requireReturn: true,
requireParamDescription: true,
requireReturnDescription: true
}],
// 检查类型注释
'jsdoc/check-types': 'error',
'jsdoc/check-tag-names': 'error'
}
};
CI/CD 集成 #
GitHub Actions #
yaml
# .github/workflows/docs.yml
name: Generate Docs
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Generate docs
run: npm run docs
- name: Deploy to GitHub Pages
if: github.event_name == 'push'
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
GitLab CI #
yaml
# .gitlab-ci.yml
stages:
- docs
generate_docs:
stage: docs
image: node:18
script:
- npm ci
- npm run docs
artifacts:
paths:
- docs/
expire_in: 1 week
only:
- main
文档验证 #
yaml
# .github/workflows/validate-docs.yml
name: Validate Docs
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Check JSDoc syntax
run: npm run docs:check
- name: Validate types
run: npm run type-check
常见问题解决 #
问题 1:类型推断不准确 #
javascript
// 问题
/**
* @param data - 数据
*/
function process(data) {
return data.name; // 类型推断失败
}
// 解决
/**
* @param {Object} data - 数据对象
* @param {string} data.name - 名称
* @returns {string} 名称
*/
function process(data) {
return data.name;
}
问题 2:可选参数处理 #
javascript
// 问题
/**
* @param {string} name - 用户名
* @param {number} age - 年龄
*/
function create(name, age) {
// age 可能是 undefined
}
// 解决
/**
* @param {string} name - 用户名
* @param {number} [age] - 年龄(可选)
*/
function create(name, age) {
if (age !== undefined) {
// 处理 age
}
}
问题 3:Promise 类型 #
javascript
// 问题
/**
* @returns {User} 用户
*/
async function getUser() {
return fetch('/api/user');
}
// 解决
/**
* @returns {Promise<User>} 用户 Promise
*/
async function getUser() {
const response = await fetch('/api/user');
return response.json();
}
问题 4:泛型函数 #
javascript
// 问题
/**
* @param value - 输入值
* @returns 输出值
*/
function identity(value) {
return value;
}
// 解决
/**
* @template T
* @param {T} value - 输入值
* @returns {T} 相同类型的输出值
*/
function identity(value) {
return value;
}
文档维护 #
定期审查 #
bash
# 检查缺失文档的函数
npm run docs:check
# 检查过时的文档
npm run docs:validate
# 更新文档
npm run docs:update
版本管理 #
javascript
/**
* @since 1.0.0
*/
function feature() {}
/**
* @deprecated 自 2.0.0 起废弃
* @see newFeature
*/
function oldFeature() {}
/**
* @version 2.1.0
* @description 新增了 xxx 功能
*/
function updatedFeature() {}
变更日志 #
javascript
/**
* 用户服务
*
* @module UserService
* @version 2.0.0
*
* @changelog
* - 2.0.0: 重构 API,支持 Promise
* - 1.5.0: 新增批量操作
* - 1.0.0: 初始版本
*/
总结 #
核心原则 #
- 清晰简洁:描述准确,避免冗余
- 保持同步:文档与代码同步更新
- 类型具体:使用具体类型,避免模糊
- 示例完整:提供可运行的示例
- 团队协作:统一规范,代码审查
检查清单 #
- [ ] 所有公共 API 都有文档
- [ ] 参数和返回值类型正确
- [ ] 描述清晰准确
- [ ] 示例可以运行
- [ ] 文档与代码同步
- [ ] 使用了正确的标签
- [ ] 类型定义完整
- [ ] 遵循团队规范
学习路径回顾 #
text
入门阶段
├── JSDoc 简介 ✓
├── 基础语法 ✓
├── 类型定义 ✓
└── 常用标签 ✓
进阶阶段
├── 高级用法 ✓
├── 配置文件 ✓
├── 插件扩展 ✓
└── 最佳实践 ✓
实战阶段
├── 项目文档实战
├── 团队规范制定
├── CI/CD 集成
└── 持续维护
恭喜你完成了 JSDoc 文档的学习!现在你已经掌握了从基础到高级的所有知识,可以开始在实际项目中编写高质量的文档了。
最后更新:2026-03-29