如何为嵌套对象的方法编写JSDoc文档?

48

我一直在尝试使用JSDoc3来生成文件的文档,但是我遇到了一些困难。这个文件(是一个Require.js模块)基本上看起来像这样:

define([], function() {

    /*
     * @exports mystuff/foo
     */
    var foo = {
        /**
         * @member
         */
        bar: {
            /**
             * @method
             */
            baz: function() { /*...*/ }
        }
    };

    return foo;
}

问题是,我无法在生成的文档中显示baz。 相反,我只得到了一个foo / foo模块的文档文件,其中列出了一个bar成员,但bar没有baz(只有指向foo源代码的链接)。
我尝试将bar的指令更改为@property,并尝试将baz的指令更改为@member@property,但这些都没有帮助。 无论我做什么,baz似乎都不想出现。
有人知道我可以使用什么指令结构来使baz出现在生成的文档中吗?
附言:我尝试阅读JSDoc网站上的页面http://usejsdoc.org/howto-commonjs-modules.html之类的页面,但它只描述了foo.bar的情况,而不是foo.bar.baz
4个回答

59
你可以使用@module@namespace@memberof相结合。
define([], function() {

    /**
     * A test module foo
     * @version 1.0
     * @exports mystuff/foo
     * @namespace foo
     */
    var foo = {
        /**
         * A method in first level, just for test
         * @memberof foo
         * @method testFirstLvl
         */
        testFirstLvl: function(msg) {},
        /**
         * Test child object with child namespace
         * @memberof foo
         * @type {object}
         * @namespace foo.bar
         */
        bar: {
            /**
             * A Test Inner method in child namespace
             * @memberof foo.bar
             * @method baz
             */
            baz: function() { /*...*/ }
        },
        /**
         * Test child object without namespace
         * @memberof foo
         * @type {object}
         * @property {method} baz2 A child method as property defination
         */
        bar2: {
            /**
             * A Test Inner method
             * @memberof foo.bar2
             * @method baz2
             */
            baz2: function() { /*...*/ }
        },
        /**
         * Test child object with namespace and property def.
         * @memberof foo
         * @type {object}
         * @namespace foo.bar3
         * @property {method} baz3 A child method as property defination
         */
        bar3: {
            /**
             * A Test Inner method in child namespace
             * @memberof foo.bar3
             * @method baz3
             */
            baz3: function() { /*...*/ }
        },
        /**
         * Test child object
         * @memberof foo
         * @type {object}
         * @property {method} baz4 A child method
         */
        bar4: {
             /**
             * The @alias and @memberof! tags force JSDoc to document the
             * property as `bar4.baz4` (rather than `baz4`) and to be a member of
             * `Data#`. You can link to the property as {@link foo#bar4.baz4}.
             * @alias bar4.baz4
             * @memberof! foo#
             * @method bar4.baz4
             */
            baz4: function() { /*...*/ }
        }
    };

    return foo;
});

根据评论进行编辑:(模块的单页解决方案)

bar4没有那个丑陋的属性表格。也就是说,从bar4中删除了@property。

define([], function() {

    /**
     * A test module foo
     * @version 1.0
     * @exports mystuff/foo
     * @namespace foo
     */
    var foo = {
        /**
         * A method in first level, just for test
         * @memberof foo
         * @method testFirstLvl
         */
        testFirstLvl: function(msg) {},
        /**
         * Test child object
         * @memberof foo
         * @type {object}
         */
        bar4: {
             /**
             * The @alias and @memberof! tags force JSDoc to document the
             * property as `bar4.baz4` (rather than `baz4`) and to be a member of
             * `Data#`. You can link to the property as {@link foo#bar4.baz4}.
             * @alias bar4.baz4
             * @memberof! foo#
             * @method bar4.baz4
             */
            baz4: function() { /*...*/ },
            /**
             * @memberof! for a memeber
             * @alias bar4.test
             * @memberof! foo#
             * @member bar4.test
             */
             test : true
        }
    };

    return foo;
});

参考文献 -

  1. 有关嵌套命名空间的另一个问题
  2. 使用替代方式使用命名空间
  3. 记录字面对象

*注意:我自己还没有尝试过。请尝试并分享结果。


1
谢谢,但那根本不起作用。最终我得到了一个空的foo文档页面(没有提到bar),以及一个没有baz方法的“全局”bar页面 :-( - machineghost
实际上,如果我直接使用你的代码,我甚至什么都得不到:我只会得到一个空白的foo页面。但是,如果我按照你的建议对我的实际代码进行类似的操作,我会得到一个等同于空白foo页面和一个没有baz的“全局”bar页面。 - machineghost
我从未意味着你必须逐字跟随我的例子。我只是说尝试使用它们。无论如何,我已经这样做了。我正在使用两种不同效果的条形图。 - Mohit
我最终添加了四个条。有许多记录内部对象的方法。请尝试并评论。我可以在具体方法上进行更详细的解释。您可以直接在上述代码上运行jsdoc。 - Mohit
它起作用了...或者至少它工作得好得多!@namespace foo.bar似乎是我需要的缺失部分。唯一仍然不太理想的是,每个子级(例如barbar2)都有自己的页面。理想情况下,我希望看到barbar2出现在foo的页面上(因为我正在尝试为foo模块生成文档页面,而不是为foo的每个部分生成一堆页面)...是否有任何办法让它们这样做? - machineghost
显示剩余4条评论

8

这是一种简单的方法:

/**
 * @module mystuff/foo
 * @version 1.0
 */
define([], function() {

/** @lends module:mystuff/foo */
var foo = {
    /**
     * A method in first level, just for test
     */
    testFirstLvl: function(msg) {},
    /**
     * @namespace
     */
    bar4: {
        /**
         * This is the description for baz4.
         */
        baz4: function() { /*...*/ },
        /**
         * This is the description for test.
         */
        test : true
    }
};

return foo;
});

请注意,jsdoc可以推断出类型baz4.baz4test,无需使用@method和@member。
至于让jsdoc3将类和命名空间的文档放在定义它们的模块的同一页上,我不知道如何做到。
我已经使用jsdoc3几个月了,用它来记录一个小型库和一个大型应用程序。在某些方面,我更喜欢迎合jsdoc3的想法,而不是为了迎合自己的意愿而输入大量的@指令。

我喜欢这个...但是唯一出现在右侧导航(假设默认模板)的是foo。希望我能够拥有这种简洁的符号加上完整的内容! - Greg Pettit

1
您无法直接记录嵌套函数。我不喜欢Prongs的解决方案,所以我使用了一个不带命名空间的不同实现(它是JS,不是 Java!)。 更新: 我更新了我的答案,以反映OP给出的确切用例(这很公平,因为使用JSdoc非常痛苦)。以下是它的工作方式:
/** @module foobar */

/** @function */
function foobarbaz() {
    /* 
     * You can't document properties inside a function as members, like you
     * can for classes. In Javascript, functions are first-class objects. The
     * workaround is to make it a @memberof it's closest parent (the module).
     * manually linking it to the function using (see: {@link ...}), and giving
     * it a @name.
     */

    /**
     * Foo object (see: {@link module:foobar~foobarbaz})
     * @name foo
     * @inner
     * @private
     * @memberof module:foobar
     * @property {Object} foo - The foo object
     * @property {Object} foo.bar - The bar object
     * @property {function} foo.bar.baz - The baz function
     */
    var foo = {

        /* 
         * You can follow the same steps that was done for foo, with bar. Or if the
         * @property description of foo.bar is enough, leave this alone. 
         */
        bar: {

            /*
             * Like the limitation with the foo object, you can only document members 
             * of @classes. Here I used the same technique as foo, except with baz.
             */

            /**
             * Baz function (see: {@link module:foobar~foo})
             * @function
             * @memberof module:foobar
             * @returns {string} Some string
             */
            baz: function() { /*...*/ }
        }
    };

    return foo;
}

不幸的是,JSdoc是Java的移植版,因此它有很多对于Java有意义但对于JS没有意义的特性,反之亦然。例如,由于在JS中函数是一等对象,它们可以被视为对象或函数。因此,做这样的事情应该可以:

/** @function */
function hello() {
  /** @member {Object} */
  var hi = {};
}

但是它不会,因为JSdoc将其识别为函数。您需要使用命名空间,我的技术与@link,或者将其变成一个类:
/** @class */
function Hello() {
  /** @member {Object} */
  var hi = {};
}

但这也没有意义。 JS中存在类吗? 不,不存在。 我认为我们真的需要找到更好的文档解决方案。我甚至在文档中看到了关于类型应如何显示的不一致性(例如{object} vs {Object})。
您还可以使用我的技术来记录closures

1
请在问题中放置您实际的代码,而不仅仅是链接。如果您能够将其调整为 OP 的嵌套 foo-bar-baz 对象文字,则会有所帮助。 - Bergi
命名空间是一种通用的编程概念。任何一种编程语言都可能更或少地明确它们,但即使在像 JS 这样不明确使用它们的语言中,它们仍然非常相关。毕竟,否则为什么 JSDoc,一个纯粹针对 JavaScript 语言(而不是 Java)的文档标准会包括这样一个标签呢? - machineghost
JS并没有真正的命名空间。它只有两个作用域:全局作用域和函数作用域。JS的命名空间是什么样子的?这是因为它是从Java移植过来的。JSdoc不直接支持许多常见的JS习惯用法,比如文档化JSON属性、闭包、嵌套函数等。 - risto

0

为了对JSDoc3中Prongs的答案进行一些改进,我只能在使用@member注释无效时,使用@instance注释才能使其正常工作。

以下是ES6示例代码:

class Test
{
    /**
     * @param {object} something
     */
    constructor(something)
    {
        this.somethingElse = something;

        /**
         * This sub-object contains all sub-class functionality.
         *
         * @type {object}
         */
        this.topology = {
            /**
             * Informative comment here!
             *
             * @alias topology.toJSON
             * @memberof! Test#
             * @instance topology.toJSON
             * 
             * @returns {object} JSON object
             */
            toJSON()
            {
                return deepclone(privatesMap.get(this).innerJSON);
            },


            ...
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接