JavaScript之注释规范化(JSDoc)
- 
            date_range 13/03/2020 00:00
 点击量:次infosortJavaScriptlabeljsdoc注释规范化格式
前言
俗话说,无规矩不成方圆;虽说代码敲出来都是交给编译器解释执行的,只要不存在语法格式错误,排版无论多么反人类都是没有问题的,但是代码除了执行外的另一个广泛用途就是阅读了,翻阅自己过去的代码、理解别人的源码,等等;所以出现了代码风格化,美化外观的同时便于阅读,这就是目前 JSLint 等工具的作用;
当然,除了代码本身外,阅读更多的可能就是代码注释了,注释本身是不会被编译器编译执行的,其作用也是为了留下一些信息,方便更好的理解代码本身;所以,注释的规范化也是一个值得思考的问题;而接下来即将介绍的 JSDoc 就是这样的一款工具;
JSDoc
根据其官网(https://jsdoc.app/index.html)的介绍,JSDoc 是一个针对 JavaScript 的 API 文档生成器,类似于 Java 中的 Javadoc 或者 PHP 中的 phpDocumentor;在源代码中添加指定格式的注释,JSDoc 工具便会自动扫描你的代码并生成一个 API 文档网站(在指定目录下生成相关的网页文件);
生成 API 文档只是一方面,其更主要的贡献在于对代码注释格式进行了规范化,你可能没用过,但多半曾经在某个地方的源码中见过类似于下面的注释格式:
/**
 * Returns the sum of a and b
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
function sum(a, b) {
    return a + b;
}
使用
工具的使用很简单,首先安装它:
npm install -g jsdoc
其次假设在一个名为 doc.js 的文件中书写以下代码:
/**
 * Returns the sum of a and b
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
function sum(a, b) {
    return a + b;
}
/**
 * Return the diff fo a and b
 * @param {number} a
 * @param {number} b
 * @returns {number}
 */
function diff(a, b) {
    return a - b;
}
然后就是在当前目录执行以下命令:
jsdoc doc.js
最后就会在当前目录下生成一个名为 out 的目录(也可以另外指定),当前目录内容就会变成像下面这样:
├── doc.js
└── out
    ├── index.html
    ├── doc.js.html
    ├── global.html
    ├── fonts
    │   ├── OpenSans-BoldItalic-webfont.eot 
    │   ├── OpenSans-BoldItalic-webfont.svg 
    │   ├── OpenSans-BoldItalic-webfont.woff
    │   ├── OpenSans-Bold-webfont.eot       
    │   ├── OpenSans-Bold-webfont.svg       
    │   ├── OpenSans-Bold-webfont.woff      
    │   ├── OpenSans-Italic-webfont.eot     
    │   ├── OpenSans-Italic-webfont.svg     
    │   ├── OpenSans-Italic-webfont.woff    
    │   ├── OpenSans-LightItalic-webfont.eot
    │   ├── OpenSans-LightItalic-webfont.svg
    │   ├── OpenSans-LightItalic-webfont.woff
    │   ├── OpenSans-Light-webfont.eot
    │   ├── OpenSans-Light-webfont.svg
    │   ├── OpenSans-Light-webfont.woff
    │   ├── OpenSans-Regular-webfont.eot
    │   ├── OpenSans-Regular-webfont.svg
    │   └── OpenSans-Regular-webfont.woff
    ├── scripts
    │   ├── linenumber.js
    │   └── prettify
    │       ├── Apache-License-2.0.txt
    │       ├── lang-css.js
    │       └── prettify.js
    └── styles
        ├── jsdoc-default.css
        ├── prettify-jsdoc.css
        └── prettify-tomorrow.css
通过浏览器访问这个 out 目录中的相关网页,就会展示类似于下面的页面内容;
主页:

指定函数页:

网页样式模板也可以更换,根据命令行参数修改即可,这里不再探究,下面主要来学习一下它的注释格式;
注释格式
完整的格式介绍请参考官网(https://jsdoc.app/index.html),目前版本是 JSDoc 3,下面只介绍几种常用的标签并配合举例;当然如果嫌手写一堆标签麻烦,现在许多编辑器(比如 VS Code)都提供了相关的插件下载,直接在插件中搜索关键词 jsdoc 就会出现许多,都是带提示或者自动识别当前代码生成的,很方便;
注释符
JSDoc 使用以下格式的注释符来对要添加的标签进行块级包裹:
/**
 * 
 * 
 */
即星号列垂直对其,第一行使用两个星号,每个星号后要添加一个空格再写内容,比如:
/**
 * 前面留一个空格,再写描述
 * 或者多行描述
 * @param {number} 关于该参数的描述
 */
行内包裹:
/** @function */
@description
也可写作 @desc,描述当前注释对象的详细信息;
/**
 * @function
 * @description 关于该函数的介绍内容
 */
function myFn() {}
/**
 * 也能在这里直接写介绍内容
 * @function
 * @description 如果这里又继续使用标签添加内容,则会覆盖第一行的介绍内容
 */
function myFn() {}
@file
注释写在文件开头,用于描述当前文件的相关信息;例如:
/**
 * @file 这是一个用于...的文件,包含了...功能
 */
 
// 然后是代码正文...
@author
描述当前文件或者代码的作者的相关信息;
/**
 * @author Jack <jack@example.com>
 */
@copyright
描述当前文件的版权相关信息
/**
 * @copyright Jack 2020
 */
@license
描述当前文件许可证相关信息;
/**
 * @license MIT
 */
或者是:
/**
 * @license
 * Copyright (c) 2015 Example Corporation Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * ...
 */
@version
描述当前项目的版本号;
/**
 * 这个版本修复了...问题
 * @version 1.2.3
 */
@since
描述某个功能是从哪个版本开始引入的;
/**
 * 提供了...功能
 * @since 1.2.1
 */
function newFn() {}
@see
类似于“另见”、“详见”的意思,引导至其他位置,也可以使用 @link 引导至某一网络地址;
/**
 * @see fn2
 */
function fn1() {}
/**
 * @see {@link http://example.com|some text}
 */
function fn2() {}
@todo
描述接下来准备做的事情;
/**
 * @todo 添加...功能
 * @todo 修复...bug
 */
function myFn() {}
@function
与 @func, @method 含义相同,描述一个函数;
/** @function */
var myFn = function() {}
@type
描述一个变量的类型;
/**
 * 一个对象类型的变量
 * @type {object}
 */
var val1 = {};
/**
 * 一个字符或者数字类型的变量
 * @type {(string|number)}
 */
var val2;
/**
 * 类型为数字或为空
 * @type {?number}
 */
var val3;
/**
 * 类型为数字或且不能为空
 * @type {!number}
 */
var val4;
/**
 * 一个 MyClass 类的实例数组
 * @type {Array.<MyClass>}
 */
var arr = new MyClass();
/**
 * 一个字符串的数组
 * @type {string[]}
 */
var arr2 = ['a', 'b', 'c'];
/**
 * 一个包含一个字符串和一个数字类型的对象
 * @type {object.<string, number>}
 */
var obj1 = {a: 'one', b: 2}
/**
 * 指定具体键和类型的对象
 * @type {{a: string, b: number}}
 */
var obj2 = {a: 'one', b: 2}
/**
 * 指定具体键和类型的命名对象
 * @type {object} obj3
 * @type {string} obj3.a
 * @type {number} obj3.b
 */
var obj3 = {a: 'one', b: 2}
@param
与 @arg, @argument 含义相同,描述一个函数的参数信息;
/**
 * 标签后跟参数类型,然后是参数名,最后是参数描述
 * @param {number} a 这里写变量的描述
 * @param {string} b - 或者加上连字符便于阅读
 * @param {string} c - 又或者这个参数有一个很长很长很长
 * 很长很长很长很长很长非常长的描述,可以这样占用多行
 */
function myFn(a, b, c) {}
/**
 * 传入的参数是个对象
 * @param {object} option - 传入的对象参数
 * @param {string} option.name - 对象的 name 属性
 * @param {number} option.age - 对象的 age 属性
 */
function myFn(option) {
    var name = option.name;
    var age = option.age;
}
/**
 * 传入的参数是个字符串组成的数组
 * @param {string[]} arr - 传入的对象参数
 */
function myFn(arr) {
    var name = option.name;
    var age = option.age;
}
/**
 * 表示某个参数是可选的
 * @param {number} a - 这是必填参数
 * @param {number} [b] - 这是可选参数
 * @param {number=} c - 可选参数的另一种表示
 */
function myFn(a, b, c) {}
/**
 * 表示可选参数的默认值
 * @param {number} a
 * @param {number} [b=3] - 默认值为 3
 */
function myFn(a, b) {}
/**
 * 参数类型的各种表示
 * @param {number} a - 类型为数字
 * @param {number|string} b - 类型为数字或字符串
 * @param {?number} c - 类型为数字或者为空(null)
 * @param {!number} d - 类型为数字且不为空
 * @param {*} e - 类型不做限制,即可以为任意类型
 */
function myFn(a, b, c, d, e) {}
/**
 * 表示具有任意多个参数的函数
 * 下面的函数返回所有传入参数的和
 * @param {...number} num - 参数个数任意,但是都是数字类型
 */
function sum(num) {
    var len = arguments.length;
    var result = 0;
    
    for (let i = 0; i < len; i++) {
        result += arguments[i];
    }
    return result;
}
@typedef
用于描述自定义的变量类型;
/**
 * 关于自定义类型的描述
 * @typedef {(string|number)} myType
 */
/**
 * 关于自定义类型的描述
 * @type {myType} val - 使用自定义的类型
 */
function myFn(val) {}
@callback
描述指定函数中作为回调函数的参数信息;
/**
 * 这是关于回调函数的描述
 * @callback myCallback
 * @param {string} aa - 回调函数接受的参数
 * @param {number} [bb] - 回调函数接受的另一个可选参数
 */
 
/**
 * 这是关于函数本身的描述
 * @param {string} a
 * @param {myCallback} callback - 回调函数
 */
function myFn(a, callback) {}
@returns
或者写作 @return,描述函数的返回值的信息;
/**
 * @param {number} a
 * @returns {number} 关于返回值的描述
 */
function myFn(a) {
    return a + 1;
}
/**
 * @param {number} a
 * @returns {(number|string)} 返回值可能是数字或字符类型
 */
function myFn2(a) {
    if (a > 1) {
        return 1;
    } else {
        return 'no.';
    }
}
@example
描述指定代码的使用示例;
/**
 * 添加示例代码(格式会被高亮展示)
 * @param {string} a
 * @param {string} b
 * @returns {string} return a concat b.
 *
 * @example
 * console.log(myFn('hello ', 'world!'));
 * // "hello world!"
 */
function myFn(a, b) {
    return a + b;
}
@class
描述一个 class 类;
/**
 * 关于该类的描述
 * @class
 */
class MyClass {}
/**
 * 或者是一个构造函数
 * @class
 */
function MyClass() {}
var ins = new MyClass();
@namespace
描述一个命名空间;
/**
 * 指定一个对象对命名空间
 * @namespace
 */
var MyNamespace = {
    /**
     * 表示为 MyNamespace.fn
     * @returns {*}
     */
    fn: function() {},
    /**
     * 表示为 MyNamespace.a
     * @type {number}
     */
    a: 1
}
/**
 * 手动指定命名空间
 * @namespace MyNamespace
 */
/**
 * 一个成员函数,MyNamespace.myFn
 * @function
 * @returns {*}
 * @memberof MyNamespace
 */
function myFn() {}
@member
描述当前类的一个成员;
/**
 * @class
 */
function MyClass() {
    /** @member {string} */
    this.name = 'andrewyghub';
    
    /**
     * 或者一个虚拟的成员
     * @member {number} age
     */
}
@memberof
描述成员所属的类;
/**
 * @class
 */
class MyClass {
    /**
     * @constructor
     * @memberof MyClass
     */
    constructor() {}
    /*
     * @param {string} val
     * @returns {*}
     * @memberof MyClass
     */
    myFn(val) {}
}
评论:
技术文章推送
手机、电脑实用软件分享
 
     微信公众号:AndrewYG的算法世界
        微信公众号:AndrewYG的算法世界
     
                    