让 JSDoc 正确记录嵌套闭包

Posted

技术标签:

【中文标题】让 JSDoc 正确记录嵌套闭包【英文标题】:Get JSDoc to correctly document nested closures 【发布时间】:2017-01-08 09:45:23 【问题描述】:

我有一个大的、结构良好的 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 本身不会很快改变结构:只有 cmets 可以合理地改变。

我希望能够使用 JSDoc 来记录这个应用程序,但是无论我给它什么,JSDoc 在这方面都失败了。在 *** 上四处寻找已经确定了处理各种知名模块系统的方法,但我还没有找到使用多重嵌套闭包的纯简 JavaScript 的可靠答案。

那么有没有人有办法让 JSDoc 正确生成 MyClass 作为“类类”构造,其中深层嵌套的函数作为该“类”的“方法”?我可以将otherFunc 标记为@private 或将其标记为隐藏,或者将myFunc 标记为@public 或将其标记为可见,但无论我尝试什么,JSDoc似乎根本不想记录任何这些嵌套函数。

【问题讨论】:

我对JSDoc不是很了解,但是遇到这种情况你可以考虑typedef。 【参考方案1】:

我知道这是一个死灵,但确实没有任何好的文档,所以就这样吧。我花了整整两天时间阅读其他人的代码并尝试弄清楚这一点。这是使用 3.6.7

基本上:

    你必须使用命名空间,但是 JSDoc 不喜欢有与函数同名的命名空间,所以你必须通过在所有函数命名空间前加上波浪号来隐藏命名空间相同的事实。 ~ 波浪线本身不会出现在文档中,但如果你没有它们,JSDoc 会感到困惑。这在我能找到的任何地方都没有真正记录,我是从 JSDoc 处理返回值的方式推断出来的。

    您需要有一个基于实际属性的“根”命名空间。 const ClosureDoc = version: "1.0.0"; 在下面的代码中,在 /** @namespace */ 标注下方。尝试删除实际对象并仅使用 /** @namespace ClosureDoc */ 不起作用。不知道为什么,这在任何地方都没有记录。

    您需要手动显式命名所有内部函数。所有作为函数的返回值也必须手动显式定义,但如果您使用* @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();

`

【讨论】:

以上是关于让 JSDoc 正确记录嵌套闭包的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 JSDoc 记录 CoffeeScript 源代码?

闭包函数

百万年薪python之路 -- 闭包

JS闭包理解

JavaScript 闭包 立即执行函数

嵌套函数和闭包