JSDoc简单应用
JSDoc 是一个根据 JavaScript 文件中注释信息,生成 JavaScript 应用程序、库或模块的 API 文档的工具。
它的本质是代码注释,但它也有一定的格式和规则。
JSDoc 注释
JSDoc 注释一般应该放置在方法或函数声明之前,它必须以 /**
开头,以便由 JSDoc 解析器识别。其他任何以 /*
、/***
或者超过 3 个星号的注释,都会被 JSDoc 解析器忽略。如以下代码所示:
js
/**
* 加法运算
*/
function plus (a, b) {}
/**
* 减法运算
*/
function minus (a, b) {}
JSDoc 注释标签
在 JSDoc 注释中有一套标准的注释标签,一般以 @
开头。如下代码所示:
js
/**
* 加法运算
* @param { number } a - 加数
* @param { number } b - 被加数
* @returns { number } 两数之和
*/
function plus (a, b) {}
/**
* 减法运算
* @param { number } a - 减数
* @param { number } b - 被减数
* @returns { number } 两数之差
*/
function minus (a, b) {}
因为 JSDoc 经历过好几个版本,为了向后兼容,所以也存在别名,比如 @param
就有以下两个别名:
@arg
@argument
在某些场景下,别名可能更加语义化。
案例说明
本文只会对个别常用案例中使用到的注释标签进行说明,并不会涉及到所有的 JSDoc 注释标签。
变量 / 常量
在 JSDoc 中,并没有变量的注释标签,它只有一个常量的注释标签 @constant
,别名为 @const
:
js
@constant [<type> <name>]
type
和 name
都是可选的:
js
/** @constant */
const A = 1
/** @const { string } B - 字符串 */
const B = ''
/**
* @constant 一个布尔标识
* @type { boolean }
* @default
*/
const C = false
@type
标签中提供了一个类型,这是可选的。另外,@default
标签在这里也是一样,这里将自动添加指定的值(如:false
)给文档。
虽然,它是一个常量的注释标签,但也可以有效地用在 var
、let
声明上:
js
/** @constant { string } */
let a = 'string'
/** @const { number } */
var b = 1
enum
@enum
标签描述一个静态属性值的全部相同属性集合。枚举类似一个属性的集合,除了枚举自己描述注释之外,其它属性都记录在容器内部的注释中。
@enum
通常与 @readonly
结合使用,作为一个枚举通常表示常量的集合:
js
/**
* @readonly
* @enum { number }
*/
const state = {
TRUE: 1,
FALSE: -1,
/** @type { boolean } */
MAYBE: true
}
函数
通过 @function
标签将一个对象标记为函数/方法:
js
const arithmetic = {
plus (a, b) {
return a + b
}
}
/** @function */
const plus = arithmetic.plus
另外,我们可以通过 @name
标签来指定该函数的名称:
js
/**
* @function
* @name plus
*/
const plus = arithmetic.plus
当然,这些只是针对生成文档时的应用,对于编辑器提示并没有什么卵用。
下面我们来了解一下如果对函数参数以及返回值进行注释:
js
const arithmetic = {
/**
* 获取两数之和
* @arg { number } a - 加数
* @arg { number } b - 减数
* @returns { number } 两数之和
*/
plus (a, b) {
return a + b
}
}
我们可以通过 @params
或别名 @arg
、@argument
等标签对函数的参数进行注释:
js
@param [<type>] name [<comment>]
@arg [<type>] name [<comment>]
@argument [<type>] name [<comment>]
通过 @returns
标签对函数的返回值进行注释:
js
@return [<type> <comment>]
在编辑器里面,当鼠标移动到对应的方法,我们应该可以看到以下的结果:
在函数中,还存在着可选参数,如以下函数所示,性别是可选的(0 表示保密,1 表示男,2 表示女):
js
function test (name, age, gender = 0) {}
我们可以将给参数名加上 []
来表示该参数是可选的:
js
/**
* Test
* @param { string } name - 名字
* @param { number } age - 年龄
* @param { number } [gender] - 性别(0 表示保密,1 表示男,2 表示女)
*/
function test (name, age, gender = 0) {}
另外,也可以给可选参数加上默认值:
js
/**
* Test
* @param { string } name - 名字
* @param { number } age - 年龄
* @param { number } [gender=0] - 性别(0 表示保密,1 表示男,2 表示女)
*/
function test (name, age, gender = 0) {}
多类型参数和可重复使用的参数
使用 |
可以表示一个参数允许不同的类型:
typescript
/**
* SayHello
* @param { string | string[] } somebody - 名称,或名称组成的数组
*/
function sayHello (somebody = 'zhangsan') {
if (Array.isArray(somebody)) {
console.log(`Hello ${somebody.join(',')}`)
} else {
console.log(`Hello ${somebody}`)
}
}
使用 *
表示一个参数允许任意类型:
js
/**
* @param { * } any - 任意类型参数
*/
function testAny (any) {}
使用 ...
表示参数个数不确定,但类型一样,也就是可重复使用的参数:
js
/**
* 求和
* @param { ...number } num - 正数或负数
*/
function sum () {
let result = 0
for (i = 0; i < arguments.length; i++) {
result += arguments[i]
}
return result
}
回调函数
如果函数接受一个回调函数作为参数,那么我们可以使用 @callback
标签来定义一个回调函数,回调函数的参数类型包含到 @param
标签中:
js
/**
* 这是一个名为 reqCallback 的回调函数,它接收一个字符串类型的参数:res
* @callback reqCallback
* @param { string } res - 返回结果
*/
/**
* 一个异步函数,接收一个 cb 作为参数
* @param { string } name - 用户名
* @param { reqCallback } cb - 回调函数
*/
function asyncFunc (name, cb) {
setTimeout(() => {
cb && cb(`Hello ${name}`)
}, 200)
}
需要注意的是,回调函数的类型声明是在另一个注释块里面。
对象参数
如果对象作为参数,我们可以把类型设置成 Object
,通过 @param
可以对该对象中其它参数进行注释:
js
/**
* 对象作为参数
* @param { Object } person - 一个人
* @param { string } person.name - TA 的名字
* @param { number } person.age - TA 的年龄
* @param { number } [person.gender] - TA 的性别
*/
function objFunc (person) {
console.log(person.name)
console.log(person.age)
console.log(person.gender)
}
同理,如果参数是一个对象数组,那我们可以这样描述:
js
/**
* 对象作为参数
* @param { Object[] } persons - 人的集合
* @param { string } persons[].name - TA 的名字
* @param { number } persons[].age - TA 的年龄
* @param { number } [persons[].gender] - TA 的性别
*/
function objFunc (persons) {
if (Array.isArray(persons)) {
persons.forEach(person => {
console.log(person.name)
console.log(person.age)
console.log(person.gender)
})
}
}
函数使用示例
有些时候,我们需应该给函数添加一些使用示例:
js
/**
* 获取参数之和
* @param { ...number } num - 正数或负数
* @return { number } 参数之和
*
* @example
* sum(1, 2)
*
* @example
* sum(-1, 2)
*/
function sum () {
let result = 0
for (i = 0; i < arguments.length; i++) {
result += arguments[i]
}
return result
}
类
@class
标签指明函数是一个构造函数,意味着该函数需要使用 new
关键字来实例化,它的别名是 @constructor
:
js
@class [<type> <name>]
@constructor [<type> <name>]
如下所示:
js
/**
* Create a new person
* @class
*/
function Person () {}
const p = new Person()
修饰符
在面向对象中,类的修饰符有三种:private
、protected
和 public
。同样在 JSDoc 也有相应的注释标签:@private
、@protected
和 @public
。
js
/**
* @class
*/
class Person {
/**
* 名字
* @public
* @type { string }
*/
name
/**
* 年龄
* @protected
* @type { number }
*/
age
/**
* 性别
* @private
* @type { number }
* @default
*/
gender = 0
/**
* @param { string } name
* @param { number } age
* @param { number } [gender]
*/
constructor (name, age, gender = 0) {
this.name = name
this.age = age
this.gender = gender
}
}
当然,少不了 @static
:
js
/**
* @class
*/
class Person {
// ...
/**
* 工具函数,将字符串转成数字
* @static
* @param { string | number } str
* @returns { number }
*/
static str2number (str) {
return Number(str)
}
}
this
@this
标签指明 this
关键字的指向:
js
/**
* @constructor
* @param { string } name
*/
function Greeter (name) {
setName.apply(this, name)
}
/**
* @this Greeter
* @param { string } name
*/
function setName (name) {
this.name = name
}
extends
使用 @extends
标签来扩展类:
js
/**
* @class
* @this Person
* @param { string } name
*/
function Person (name) {
this.name = name
}
/**
* @class
* @extends Person
*/
function Male () {}
Male.prototype = Person.prototype
自定义一个类型
通过 @typedef
可以自定义一个类型。
js
/**
* @typedef { Object } Person
* @property { string } name - 名字
* @property { number } age - 年龄
* @property { number } [gender] - 性别
*/
/**
* @param { Person } person
*/
function test (person) {
console.log(person.name, person.age, person.gender)
}
接口的返回值
利用自定义类型来定义一个接口的返回值类型:
js
/**
* @template T
* @typedef ResponseData
* @property { code } number
* @property { message } string
* @property { T } data
*/
/**
* @typedef { Object } UserInfo
* @property { string } name
* @property { number } age
* @property { number } [gender]
* @property { Skill[] } [skills]
* @property { UserInfo[] } [friends]
*/
/**
* @typedef Skill
* @type { '唱' | '跳' | 'Rap' | '篮球' }
*/
/**
* 获取用户信息
* @param { string } url
* @returns { Promise<ResponseData<UserInfo>> }
*/
function getUserInfo (url) {
return axios.get(url)
}
const zhangsan = getUserInfo('https://www.baidu.com').then(res => {
console.log(res.data.skills)
})
这里需要注意的是,在 JSDoc 中,需要使用 @template
来标识一个泛型类型。
其他
@since
@since
表示一个功能是哪个版本被加入的:
js
/**
* 获取随机数
* @since 1.0.0
* @return { number }
*/
function getRandom () {
return Math.random()
}
@deprecated
@deprecated
表示该功能已经被废弃:
js
/**
* @deprecated since version 1.2.3
*/
function oldFunc () {}
@see
@see
表示可以参考另一个标识符的文档,或一个外部资源:
js
/**
* @see {@link bar}
* @see bar
*/
function foo () {}
/**
* @see {@link foo}
* @see {@link https://www.baidu.com}
*/
function bar () {}
@todo
@todo
记录一个需要完成的任务:
js
/**
* @todo Implement this function.
* @todo Write the documentation.
*/
function test (a) {
}