让JSDoc正确记录嵌套闭包的文档

6
我有一个大型、结构良好的JavaScript对象,类似于以下内容:
/**
 * My 'class' begins here.  JSDoc barfs on this.
 */
var MyClass = (function(window, document, $) {

    return function(options) {

        "use strict";

        var
            x = 123,

            /**
             * This is a "public" function.
             */
            myFunc = function() { /*...*/ },

            /**
             * This is some other "private" function.
             */
            otherFunc = function() { /*...*/ };

        return {
            myFunc: myFunc
        };
    };

})(window, document, window.jQuery);

实际上,最外层的闭包用于控制内部闭包看到的全局范围,该闭包实现了一种模块模式:内部函数实际上是构造函数,其嵌套函数实际上是方法,返回的对象实际上是“公共”部分的列表。
JSDoc 不支持此模式。
(记录一下,我使用的是 JSDoc 3.4。)
我在这段代码的许多地方尝试了几个变体,包括 @lend、@export、@namespace 和 @memberof,但无论我做什么,JSDoc 都不会注意到任何内部函数 - 它不仅“不将它们与正确的东西相关联”;它根本不在任何输出文件中包含它们。
这是一个优秀的模式,可以紧密封装经典的 JavaScript,不仅封装其内部,而且封装其依赖项,我们的真实应用程序在许多许多千行代码中使用这种模式。因此,我们的 JavaScript 结构不会很快改变:只有注释可以合理地更改。
我希望能够使用JSDoc来记录此应用程序,但无论我提供什么,JSDoc都会失败。在StackOverflow上搜索发现了处理各种知名模块系统的方法,但对于使用多重嵌套闭包的纯JavaScript,我没有找到确定的答案。
因此,有人知道如何使JSDoc正确生成MyClass作为“类似”的结构,并将深度嵌套在其中的函数作为该“类”的“方法”?我可以将otherFunc标记为@private之类的标记以将其标记为隐藏,或者将myFunc标记为@public之类的标记以将其标记为可见,但无论我尝试什么,JSDoc似乎都不想记录任何这些嵌套函数。

我对JSDoc不是很熟悉,但在这种情况下,您可能需要考虑[typedef](http://usejsdoc.org/tags-typedef.html)。 - JDB
1个回答

2
我知道这是一篇旧帖,但确实没有任何关于此的好文档,所以我来介绍一下。我花了整整两天的时间阅读其他人的代码和进行试验才弄明白。这是使用3.6.7版本的。
基本上:
1. 您必须使用命名空间,但JSDoc不喜欢将命名空间命名为函数相同的名称,因此您必须通过在所有函数命名空间前加上波浪线来隐藏命名空间相同的事实。 ~这些波浪线本身不会显示在文档中,但如果没有它们,JSDoc就会感到困惑。我在任何地方都找不到这个真正的文档,并且我从JSDoc处理返回值的方式中推断出它来的。
2. 您需要有一个基于实际属性的“根”命名空间。在下面的代码中,const ClosureDoc = {version: "1.0.0"};位于/** @namespace */之下的位置。尝试删除实际对象并仅使用/** @namespace ClosureDoc */是无效的。不知道原因,也没有任何文档记录。
3. 您需要手动显式命名所有内部函数。所有作为函数返回值的返回值也必须手动定义,但是如果您使用* @returns {outerScope~innerScope}(注意波浪线),则实际上不需要@typedef。
总的来说,这似乎是对于非常合理的代码获取非常简单的结果而进行的荒谬的手把手教学。但确实可以做到。
'use strict';
/** @namespace */
const ClosureDoc = {version: "1.0.0"};

/**
 * Outer scope is used to enclose the inner scope
 * @function outerScope
 * @returns {outerScope~innerScope}
 * @returns {outerScope~logInnerMap}
 * @memberof ClosureDoc
 */
function outerScope () {
    /**@namespace ClosureDoc.~outerScope */
    const outerState = {
        innerMap: {}
    }

    const newInnerScope = (name) => (outerState.innerMap[name] = innerScope(name));
    const namedInnerScope = (name) => !(name in outerState.innerMap) ? newInnerScope(name) : outerState.innerMap[name];

    /**
     * Inner Scope is used inside the outer scope
     * @function innerScope
     * @param {string} name
     * @returns {innerScope~logScopeName}
     * @memberof ClosureDoc.~outerScope
     */
    function innerScope(name) {
        /**@namespace ClosureDoc.~outerScope.~innerScope */
        /**
         * Logs the name passed to the inner scope
         * @function logScopeName
         * @memberof ClosureDoc.~outerScope.~innerScope
         */
        function logScopeName() {
            console.log(name);
        }
        return {
            logScopeName
        }
    } 
    /**
     * Logs the map of all scope names
     * @function logInnerMap
     * @memberof ClosureDoc.~outerScope
     */
    function logInnerMap() {
        console.log(outerState.innerMap);
    }
   return {
       namedInnerScope,
       logInnerMap
    }
}

const outer = outerScope();
const inner_1 = outer.namedInnerScope("Bob");
const inner_2 = outer.namedInnerScope("Dole");
inner_1.logScopeName();
inner_2.logScopeName();
outer.logInnerMap();

`


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