1.JSDoc的介绍
JSDoc是一种针对Javascript的注释。利用这种注释,我们可以提高文档的可读性。JSDoc主要有三个作用:
- 通过注释说明让维护者更快更全面地了解函数
- 约束Javascript的变量类型,部分IDE会做类型校验
- 关联代码生成HTML说明文档
2.JSDoc的例子
如何生成说明文档请看下文。
1.普通函数
/**
* @author Ocean
* @since 1.0.1
* @name fn
* @description 该函数的描述...
* @function
* @param {String} str 类型为String,名为str的变量...
* @param {Number} num 类型为Number,名为num的变量...
* @return {Array} 返回类型为Array的变量
* @example <caption>Example usage of fn.</caption>
* // returns ['5', 10]
* fn('5', 10);
*/
function fn(str,num){
return [str,num]
}
补充说明:
@author:此代码的作者@function:表明这段代码定义的是一个函数,同类的标注有@module(模块),@class(类),@generator(生成器)等。@since:说明该类或者函数或者变量是在哪个版本添加的,以上面为例子则是在1.0.1添加的。此处也可以替换成@version 1.0.1,所表示的意义相同。@example:提供一个如何使用该函数的例子
生成HTML文档效果:
2.私有异步函数
/**
* @private
* @async
* @function
* @param {String} str
* @return {Symbol}
*/
async function _fn(str){
return Symbol(str)
}
补充说明:
@private:说明此函数为私有。标注私有后,对应的说明文档不会显示该函数的说明。同类的标注有@public,@protected(仅可在当前module中调用),@package(仅可在当前目录中调用)@async:用于被async声明的函数中,表示该函数为异步函数
因为被标注@private,所以说明文档没有该函数的说明。
3.常数变量
/**
* @constant
* @default
* @deprecated
*/
const RED = 0xff0000
补充说明:
@constant:说明该变量是常量@default:在生成的说明文档中显示该常量值@deprecated:说明该变量已被弃用,可能在下一个大版本中去除
生成HTML文档效果:
4.全局变量对象
/**
* @global
* @namespace Config
* @property {object} config.defaults - The default values for parties.
* @property {number} config.defaults.players - The default number of players.
* @property {string} config.defaults.level - The default level for the party.
* @property {object} config.defaults.treasure - The default treasure.
* @property {number} config.defaults.treasure.gold - How much gold the party starts with.
*/
var config = {
defaults: {
players: 1,
level: 'beginner',
treasure: {
gold: 0
}
}
}
补充说明:
@global:说明该变量为全局变量@namespace:标记指示对象为其成员创建名称空间。命名空间的名称默认为对象名,也可以自定义如例子所示定义成Config。@property:用于标注对象或类中的属性,经过嵌套标注后生成的文档有更可观的层次结构。如下图:
生成HTML文档效果:
5.构造函数
/**
* @constructor
* @classdesc 类描述...
* @param {number} num1
*
*/
function Example(num1,num2){
/**
* 关于num1变量的描述....
* @instance
*/
this.num1=num1
/**
* 关于num3变量的描述....
* @instance
*/
this.num2=2
/**
* 关于fn1函数的描述....
* @instance
*/
this.fn1=function(){
}
}
/**
* @static
* @readonly
*/
Example.prototype.num3=3
**补充说明:
**
@constructor:说明此对象为构造器,也可以用@class替代。@instance:被标记的变量会当作其父对象的实例成员。@static:表示被标记的变量为静态变量,所谓静态变量即可以不通过实例化父类的情况下访问该变量,如Math.ramdom。同样的,上述代码也可以通过Example.num3访问。- @readonly:表示被标记的变量只读,常用于常量和类中的get函数。
生成HTML文档效果:
6.类
/**
* @extends Shape
*/
class Rectangle extends Shape{
/**
*
* @param {number} height - 矩形的高
* @param {numer} width - 矩形的宽
*/
constructor(height,width){
this.height = height
this.width = width
}
/**
* @readonly
* @returns {number} - 返回体积
*/
getArea(){
return this.height*this.width
}
}
补充说明:
引用自官网关于ES 2015 Classes:
JSDoc 3 makes it easy to document classes that follow the ECMAScript 2015 specification. You don't need to use tags such as @class and @constructor with ES 2015 classes—JSDoc automatically identifies classes and their constructors simply by parsing your code. ES 2015 classes are supported in JSDoc 3.4.0 and later.
JSDoc3.4.0后会自动识别被其他tag注解的class,所以不需要额外加上@class或@constructor。
- @extends:表示所继承的类
生成HTML文档效果:
7.modules
这里就直接贴官网,不详细说了:
8.更多@tag
更多注解请直接看@block-tags
2.JSDoc带来的类型检查
1.VSCode自动检查类型
在VSCode下使用JSDoc,VSCode内置的type-checking插件会自动推导出类型出来。
那上面第一个例子,也就是普通函数的代码来检测,可得到以下效果:
甚至当你通过变量自身函数得到另一个变量时,这个变量的类型也可以被检测到:
2.泛型约束
首先要解释什么是泛型,用上面例子修改一下,成为下面的代码:
/**
* 省略部分tag
* @param {String} temp1
* @param {String} temp2
* @return {Array<String>}
*/
function fn(temp1,temp2){
return [temp1,temp2]
}
此时我们通过fn('1','2')调用后会得出子元素为String类型的列表。
可是如果该函数面对的业务不局限于只传入String类型的参数,还可能传入Number或者Object类型的参数时,那JSDoc的已经写死的类型约束就是一个鸡肋。
此时JSDoc中的泛型就是解决这种场景而诞生的。
所谓泛型就是,我们把泛型定义在类或者函数上时,当用户在调用这个类或者函数,才把类型确定下来。
我们把上面的代码修改一下:
/**
* 省略部分tag
* @template T
* @param {T} temp1
* @param {T} temp2
* @return {Array<T>}
*/
function fn(temp1,temp2){
return [temp1,temp2]
}
此处用@template标记T时说明T是泛型类,之后在调用时,无论是传入Number类型还是String类型的参数,VSCode都会推出最后返回的是Array还是Array的变量,如下所示:
3.如何生成说明文档
1.安装
npm i jsdoc -D
2.配置
(1)jsdoc.json
在根目录添加jsdoc.json配置文件,配置如下:
{
"plugins":[],
"source": {
"include": [ "src/" ],
"exclude": [ "src/libs" ],
"includePattern": ".+\\.js(doc|x)?$",
"excludePattern": "(^|\\/|\\\\)_"
},
"opts": {
"template": "templates/default",
"encoding": "utf8",
"destination": "./docs/",
"recurse": true,
"verbose": false
}
}
说明:
plugins:表示用到的插件。JSDoc有蛮多内置的插件,例如"plugins/markdown":可以在@author,@classdesc等注解中用markdown写文字说明,更多关于"plugins/markdown"的说明请看官方文档plugins-markdown。例子中的配置不用任何插件。source.include:指定应该生成说明文档的文件的路径source.exclude:指定不生成说明文档的文件的路径source.includePattern:用正则表达式指定要生成说明文档的文件路径。例子中的配置是指定以.js,.jsdoc和.jsx结尾的文件会生成说明文档source.excludePattern:用正则表达式指定不生成说明文档的文件路径。例子中的配置是指定以下划线_开头的目录和下划线_开头的文件名不会生成说明文档opts.template:说明文档的生成模板。例子中用的是JSDoc自带的默认模板。除了默认的也可以使用第三方模板,如docdash、minamiopts.encoding: 说明文档的编码opts.destination:说明文档的生成输出路径。例子中是生成在名为docs的目录里opts.recurse:是否递归扫描子目录文件opts.verbose:生成过程中是否输出详细信息
跟详细配置请点击about-configuring-jsdoc
(2)package.json
在script中添加指令,如下所示:
"scripts": {
"docs": "jsdoc -c jsdoc.json"
}
3.运行
直接cmd运行npm run docs即可在docs目录中生成说明文档
4.何时使用JSDoc
其实不同项目有不同的代码规则。我偏向于Angular Team Specification中写到的:
All public API methods must be documented with ngdoc, an extended version of jsdoc (we added support for markdown and templating via @ngdoc tag).
即,必须对每个公共函数用JSDoc注释清楚,其他的不作要求。