【问题标题】:How do I JSDoc A Nested Object's Methods?我如何 JSDoc 嵌套对象的方法?
【发布时间】:2013-10-14 09:19:20
【问题描述】:

我一直在尝试使用 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

【问题讨论】:

    标签: javascript requirejs jsdoc jsdoc3


    【解决方案1】:

    您可以将@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 没有那个丑陋的属性表。即 @property 从 bar4 中删除。

    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. Another Question about nested namespaces
    2. For alternative way of using Namespaces
    3. Documenting literal objects

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

    【讨论】:

    • 谢谢,但这根本不起作用。我最终得到了一个 foo 文档页面,上面什么都没有(没有提到 bar),以及一个没有 baz 方法的“全局” bar 页面:-(
    • 实际上,如果我从字面上使用您的代码,我什至不明白:我只是得到一个没有任何内容的 foo 页面。但是,如果我用我的实际代码做一些类似于你建议的事情,我会得到一个没有任何内容的 foo 页面和一个没有任何内容的“全局”栏页面(即没有 baz)。
    • 我从来没有想过你必须按照我的例子字面意思。我只是说尝试使用它们。无论如何。我做到了。我放了两种方式吧,都有不同的效果。
    • 我最终添加了四个小节。有很多方法可以记录内部对象。请尝试并发表评论。我可以更多地解释具体的方法。你可以直接在上面的代码上运行jsdoc。
    • 它工作了......或者至少它工作得好多了! @namespace foo.bar 似乎是我需要的缺失部分。唯一仍然不太理想的是每个子级别(例如barbar2)都有自己的页面。理想情况下,我希望看到barbar2 出现在foo 的页面上(因为我正在尝试为 foo 模块生成文档页面,而不是为每个 foo 生成一堆页面) ...有什么办法可以让他们这样做吗?
    【解决方案2】:

    这是一个简单的方法:

    /**
     * @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 几个月了,用它记录了 small librarylarge application。我更喜欢在某些领域屈从于 jsdoc3 的意愿,而不是必须键入大量的 @-directives 来使其符合我的意愿。

    【讨论】:

    • 我喜欢这个...但唯一出现在正确导航(假设默认模板)的是 foo.希望我能有这个符号的简洁加上完整的内容!
    【解决方案3】:

    您不能直接记录嵌套函数。我不喜欢 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}{Object})。

    你也可以用我的技术记录closures

    【讨论】:

    • 请将您的实际代码放入问题中,而不是仅链接它。如果您可以将其调整为 OP 的嵌套 foo-bar-baz 对象文字,这也会有所帮助。
    • 命名空间是一个通用的编程概念。任何给定的语言都可能或多或少地明确说明它们,但即使在像 JS 这样的语言中,它们的使用并不明确,它们仍然非常相关。毕竟,JSDoc,一个纯粹用于 JavaScript 语言(不是 Java)的文档标准,为什么要包含这样的标签?
    • JS 并没有真正的命名空间。它只有两个作用域:全局作用域和函数作用域。 JS 的命名空间是什么样的?它在那里是因为它是 Java 的一个端口。 JSdoc 不直接支持很多常见的 JS 习惯用法,比如记录 JSON 属性、闭包、嵌套函数等。
    【解决方案4】:

    只是为了改进 Prongs 对 JSDoc3 的回答,我只有在使用 @instance 注释代替 @member 时才能让它工作。

    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);
                },
    
    
                ...
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-08-23
      • 2011-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多