第 29 章. JSDoc:生成 API 文档
目录
购买本书
(广告,请不要屏蔽。)

第 29 章. JSDoc:生成 API 文档

这是一个常见的开发问题:您已经编写了供他人使用的 JavaScript 代码,并且需要一份美观的 HTML API 文档。在 JavaScript 世界中,生成 API 文档的事实上的标准工具是JSDoc[23] 它仿照其 Java 对应物 JavaDoc 建模。

JSDoc 接收带有 /** */ 注释(以星号开头的普通块注释)的 JavaScript 代码,并为其生成 HTML 文档。例如,给定以下代码:

/** @namespace */
var util = {
    /**
     * Repeat <tt>str</tt> several times.
     * @param {string} str The string to repeat.
     * @param {number} [times=1] How many times to repeat the string.
     * @returns {string}
     */
    repeat: function(str, times) {
        if (times === undefined || times < 1) {
            times = 1;
        }
        return new Array(times+1).join(str);
    }
};

生成的 HTML 在 Web 浏览器中显示,如图29-1所示。

JSDoc 网站上的自述文件介绍了如何安装和调用此工具。

JSDoc 基础知识

JSDoc 的全部内容都是关于记录实体(函数、方法、构造函数等)。这是通过实体之前的注释实现的,这些注释以 /** 开头。

语法

让我们回顾一下开头显示的注释:

/**
 * Repeat <tt>str</tt> several times.
 * @param {string} str The string to repeat.
 * @param {number} [times=1] How many times to repeat the string.
 * @returns {string}
 */

这演示了一些 JSDoc 语法,它由以下几部分组成

JSDoc 注释
这是一个 JavaScript 块注释,其第一个字符是星号。这造成了一种错觉,即标记 /** 启动了这样的注释。
标签
您可以通过以标签(以 @ 符号为前缀的关键字)开头的行来构建注释。 @param 是前面代码中的一个示例。
HTML
您可以在JSDoc 注释中自由使用 HTML。例如,<tt> 以等宽字体显示单词。
类型注释

您可以通过大括号中的类型名称来记录实体的类型。变体包括:

  • 单一类型:@param {string} name
  • 多种类型:@param {string|number} idCode
  • 一种类型的数组:@param {string[]} names
名称路径

在 JSDoc 注释中,所谓的名称路径用于引用实体。此类路径的语法如下

myFunction
MyClass
MyClass.staticMember
MyClass#instanceMember

通常(由)构造函数实现。例如,静态成员是构造函数的属性。JSDoc 对实例成员有广泛的定义。它表示可以通过实例访问的所有内容。因此,实例成员包括实例属性和原型属性。

基本标签

以下是基本元数据标签:

@fileOverview 描述

标记描述整个文件的 JSDoc 注释。例如

/**
 * @fileOverview Various tool functions.
 * @author <a href="mailto:[email protected]">John Doe</a>
 * @version 3.1.2
 */
@author
指的是编写正在记录的实体的人。
@deprecated
表示不再支持该实体。最好记录要使用的替代方案。
@example

包含一个代码示例,说明如何使用给定的实体

/**
 * @example
 * var str = 'abc';
 * console.log(repeat(str, 3)); // abcabcabc
 */

用于链接的基本标签如下

@see

指向相关资源

/**
 * @see MyConstructor#myMethod
 * @see The <a href="http://example.com">Example Project</a>.
 */
{@link ...}
工作方式类似于 @see,但可以在其他标签中使用。
@requires resourceDescription
指示文档化实体需要的资源。资源描述是名称路径或自然语言描述。

版本控制标签包括以下内容

@version versionNumber

指示文档化实体的版本。例如

@version 10.3.1
@since versionNumber

指示文档化实体自哪个版本开始可用。例如

@since 10.2.0

记录函数和方法

对于函数和方法,您可以记录参数、返回值和它们可能抛出的异常:

@param {paramType} paramName 描述

描述名称为 paramName 的参数。类型和描述是可选的。以下是一些示例:

@param str The string to repeat.
@param {string} str
@param {string} str The string to repeat.

高级功能

  • 可选参数

    @param {number} [times] The number of times is optional.
  • 具有默认值的可选参数

    @param {number} [times=1] The number of times is optional.
@returns {returnType} 描述
描述函数或方法的返回值。可以省略类型或描述。
@throws {exceptionType} 描述
描述在函数或方法执行期间可能抛出的异常。可以省略类型或描述。

内联类型信息(“内联文档注释”)

两种方法可以为参数和返回值提供类型信息。首先,您可以将类型注释添加到 @param@returns

/**
 * @param {String} name
 * @returns {Object}
 */
function getPerson(name) {
}

其次,您可以内联类型信息

function getPerson(/**String*/ name) /**Object*/ {
}

记录变量、参数和实例属性

以下标签用于记录变量、参数和实例属性:

@type {typeName}

文档化的变量是什么类型?例如:

/** @type {number} */
var carCounter = 0;

此标签也可用于记录函数的返回类型,但在这种情况下,@returns 更可取。

@constant

一个标志,指示文档化的变量具有常量值。

/** @constant */
var FORD = 'Ford';
@property {propType} propKey 描述

在构造函数注释中记录实例属性。例如:

/**
 * @constructor
 * @property {string} name The name of the person.
 */
function Person(name) {
    this.name = name;
}

或者,实例属性可以记录如下

/**
 * @class
 */
function Person(name) {
    /**
     * The name of the person.
     * @type {string}
     */
    this.name = name;
}

使用哪种样式是个人喜好问题。

@default defaultValue

参数或实例属性的默认值是什么?例如:

/** @constructor */
function Page(title) {
    /**
     * @default 'Untitled'
     */
     this.title = title || 'Untitled';
}

记录类

JSDoc 区分类和构造函数。前一个概念更像是一种类型,而构造函数是实现类的一种方式。JavaScript 用于定义类的内置方法是有限的,这就是为什么有许多 API 可以帮助完成这项任务的原因。这些 API 各不相同,通常是根本性的不同,因此您必须帮助 JSDoc 弄清楚发生了什么。以下标签可以让您做到这一点:

@constructor
将函数标记为构造函数。
@class
将变量或函数标记为类。在后一种情况下,@class@constructor 的同义词。
@constructs
记录一个方法设置实例数据。如果存在这样的方法,则在那里记录该类。
@lends namePath

指定以下对象字面量贡献给哪个类。有两种贡献方式。

  • @lends Person#:对象字面量将实例成员贡献给 Person
  • @lends Person:对象字面量将静态成员贡献给 Person
@memberof parentNamePath
文档化的实体是指定对象的成员。应用于对象字面量的 @lends MyClass# 与使用 @memberof MyClass# 标记该字面量的每个属性具有相同的效果。

定义类的最常见方法是:通过构造函数、通过对象字面量以及通过具有 @constructs 方法的对象字面量。

通过构造函数定义类

要通过构造函数定义类,您必须标记构造函数;否则,它不会被记录为类。仅大写并不能将函数标记为构造函数:

/**
 * A class for managing persons.
 * @constructor
 */
function Person(name) {
}

通过对象字面量定义类

要通过对象字面量定义类,您需要两个标记。首先,您需要告诉 JSDoc 给定变量保存了一个类。其次,您需要将对象字面量标记为定义一个类。您可以通过 @lends 标签来完成后者:

/**
 * A class for managing persons.
 * @class
 */
var Person = makeClass(
    /** @lends Person# */
    {
        say: function(message) {
            return 'This person says: ' + message;
        }
    }
);

通过具有 @constructs 方法的对象字面量定义类

如果对象字面量有一个 @constructs 方法,您需要告诉 JSDoc,以便它可以找到实例属性的文档。类的文档移动到该方法:

var Person = makeClass(
    /** @lends Person# */
    {
        /**
         * A class for managing persons.
         * @constructs
         */
        initialize: function(name) {
            this.name = name;
        },
        say: function(message) {
            return this.name + ' says: ' + message;
        }
    }
);

如果省略 @lends,则必须指定方法所属的类

var Person = makeClass({
        /**
         * A class for managing persons.
         * @constructs Person
         */
        initialize: function(name) {
            this.name = name;
        },
        /** @memberof Person# */
        say: function(message) {
            return this.name + ' says: ' + message;
        }
    }
);

子类化

JavaScript 本身不支持子类化。当您在代码中进行子类化时(无论是手动还是通过库),您都必须告诉 JSDoc 发生了什么:

@extends namePath

表示文档化的类是另一个类的子类。例如

/**
 * @constructor
 * @extends Person
 */
function Programmer(name) {
    Person.call(this, name);
    ...
}
// Remaining code for subclassing omitted

其他有用的标签

所有这些标签都在JSDoc 网站上有记录

  • 模块化:@module@exports@namespace
  • 自定义类型(用于虚拟实体,例如回调,您可以记录其签名):@typedef@callback
  • 法律事项:@copyright@license
  • 各种对象:@mixin@enum


[23] JSDoc 网站是本章的主要来源;一些例子是从它那里借来的。

下一页:30. 库