繁体   English   中英

JSDoc:我如何记录`var self = this;`?

[英]JSDoc: How do I document `var self = this;`?

只要您使用this关键字,JSDoc 就非常擅长获取在类上定义的方法和属性,例如:

/** @class */
function Person(name) {
  /** This person's name */
  this.name = name;

  /** Greet someone */
  this.greet = function(person) {
    return 'Hey there, '+person.name;
  };

  /** Log a greeting to the browser console */
  this.logGreeting = function(person) {
    console.log(this.greet(Person));
  };
}

这将生成带有“Class Person”页面的文档,其中列出了name作为 Member 和greet()logGreeting()作为方法。

但是当我遇到一个需要使用self = this模式的复杂案例时,事情就开始出现问题:

/** @class */
function Person(name) {
  var self = this;

  /** This person's name */
  self.name = name;

  /** Greet someone */
  self.greet = function(person) {
    return 'Hey there, '+person.name;
  };

  /** Log a greeting to the browser console */
  self.logGreeting = function(person) {
    console.log(self.greet(Person));
  };

  /** Log a greeting to the browser console after some delay */
  self.logGreetingDelayed = function(person, delay) {
    setTimeout(function() { self.logGreeting(person); }, delay);
  };
}

此示例生成一个Class Person页面,但它没有name member 或任何方法。

我已经看到您可以@memberof使用@memberof手动将每个成员和方法附加到类,但这真的很冗长,我想知道是否有办法告诉 JSDoc self指的是类。

(顺便说一句,我正在使用 JSDoc 3.4,以防万一。)

@alias注释可用于告诉 JSDoc 将self视为对类的引用。 实际上,从技术上讲,您需要将self别名为类的原型,而不仅仅是类本身的名称(以我不完全理解的方式破坏了东西)。 为此,您需要将@alias设置为Person# 1

/** @class */
function Person(name) {
  /** @alias Person# */
  var self = this;

  /** This person's name */
  self.name = name;

  /** Greet someone */
  self.greet = function(person) {
    return 'Hey there, '+person.name;
  };

  /** Log a greeting to the browser console */
  self.logGreeting = function(person) {
    console.log(self.greet(Person));
  };

  /** Log a greeting to the browser console after some delay */
  self.logGreetingDelayed = function(person, delay) {
    setTimeout(function() { self.logGreeting(person); }, delay);
  };
}

1:从技术上讲, Person#等效于Person.prototype ,因为尾随#指的是对象的原型(据我所知;可以更正)。 话虽这么说, this实际上指的是一个实例,这是一样的原型,所以我不推荐使用这个符号,因为它使更多的评论混淆。 幸运的是,原型方法和真正的实例方法之间的 JSDoc 输出没有区别,所以不要太担心Person#符号。

替代方法相同,包括完整性,但可能应该避免:

// ...

/** @alias Person.prototype */
var self = this;

// ...

您正在使这个(请原谅双关语)变得比它需要的更复杂。 你的设计有很多问题。

  1. 您不需要使用this来设置原型。 我非常喜欢像这样将对象InstantiationInitialization范式分开:

     /** @class */ function Person() {} Person.prototype = { /** This person's name * @return {Person} */ init: function(name) { this.name = name; return this; }, };
  2. Greet已经在一个对象上工作,你不需要传入第二个对象:

     /** Greet someone */ greet: function() { return 'Hey there, '+this.name; },

    这也简化了logGreeting

     /** Log a greeting to the browser console */ logGreeting: function() { console.log(this.greet()); },
  3. 但是,假设您确实想将第二个对象(人)传递给您的logGreeting ,则它错误地传递了Class而不是Object 应该是这样的:

     /** Greet someone */ self.greet = function(person) { return 'Hey there, '+person.name; }; /** Log a greeting to the browser console */ self.logGreeting = function(person) { console.log(self.greet(person)); // BUG: was Person instead of person };
  4. 您不应该使用self来设置原型——您首先错误地使用了使用self的原因:它们用于需要引用对象的回调

例如,让我们添加一个人重命名时的回调:

        rename: function(newName) {
            var self = this;
            var cbRename = function() {
                self.onRename( self.name, newName ); // Why self is needed
                self.name = newName;
            };

            setTimeout( cbRename, 1 );
        },

        /** Callback triggered on rename */
        onRename: function(oldName,newName) {
            console.log( "The person formally known as: '" + oldName + "'" );
            console.log( "Is now known as: '"              + newName + "'" );
        },

将所有内容放在一个示例中:

 /** @class */ function Person() {} Person.prototype = { /** This person's name * @return {Person} */ init: function(name) { this.name = name; return this; }, /** Greet someone */ greet: function() { return 'Hey there, '+this.name; }, /** Log a greeting to the browser console */ logGreeting: function() { console.log(this.greet()); }, rename: function(newName) { var self = this; var cbRename = function() { self.onRename( self.name, newName ); self.name = newName; }; setTimeout( cbRename, 1 ); }, /** Callback triggered on rename */ onRename: function(oldName,newName) { console.log( "The person formally known as: '" + oldName + "'" ); console.log( "Is now known as: '" + newName + "'" ); }, }; var alice = new Person().init( 'Alice' ); console.log( alice ); alice.logGreeting(); alice.rename( 'Bob' );

生成这个 JSdoc3 html:

 <div id="main"> <h1 class="page-title">Class: Person</h1> <section> <header> <h2>Person</h2> </header> <article> <div class="container-overview"> <hr> <h4 class="name" id="Person"><span class="type-signature"></span>new Person<span class="signature">()</span><span class="type-signature"></span></h4> <dl class="details"> <dt class="tag-source">Source:</dt> <dd class="tag-source"><ul class="dummy"><li> <a href="person.js.html">person.js</a>, <a href="person.js.html#line2">line 2</a> </li></ul></dd> </dl> </div> <h3 class="subsection-title">Methods</h3> <hr> <h4 class="name" id="greet"><span class="type-signature"></span>greet<span class="signature">()</span><span class="type-signature"></span></h4> <div class="description"> Greet someone </div> <dl class="details"> <dt class="tag-source">Source:</dt> <dd class="tag-source"><ul class="dummy"><li> <a href="person.js.html">person.js</a>, <a href="person.js.html#line17">line 17</a> </li></ul></dd> </dl> <hr> <h4 class="name" id="init"><span class="type-signature"></span>init<span class="signature">()</span><span class="type-signature"> → {<a href="Person.html">Person</a>}</span></h4> <div class="description"> This person's name return {Person} </div> <dl class="details"> <dt class="tag-source">Source:</dt> <dd class="tag-source"><ul class="dummy"><li> <a href="person.js.html">person.js</a>, <a href="person.js.html#line9">line 9</a> </li></ul></dd> </dl> <hr> <h4 class="name" id="logGreeting"><span class="type-signature"></span>logGreeting<span class="signature">()</span><span class="type-signature"></span></h4> <div class="description"> Log a greeting to the browser console </div> <dl class="details"> <dt class="tag-source">Source:</dt> <dd class="tag-source"><ul class="dummy"><li> <a href="person.js.html">person.js</a>, <a href="person.js.html#line23">line 23</a> </li></ul></dd> </dl> <hr> <h4 class="name" id="onRename"><span class="type-signature"></span>onRename<span class="signature">()</span><span class="type-signature"></span></h4> <div class="description"> Callback triggered on rename </div> <dl class="details"> <dt class="tag-source">Source:</dt> <dd class="tag-source"><ul class="dummy"><li> <a href="person.js.html">person.js</a>, <a href="person.js.html#line38">line 38</a> </li></ul></dd> </dl> </article> </section> </div>

为什么使用变量来接收this而不是将this与箭头函数一起使用?

/** @class */
function Person(name) {

  /** This person's name */
  this.name = name;

  /** Greet someone */
  this.greet = function(person) {
    return 'Hey there, '+person.name;
  };

  /** Log a greeting to the browser console */
  this.logGreeting = function(person) {
    console.log(this.greet(person));
  };

  /** Log a greeting to the browser console after some delay */
  this.logGreetingDelayed = function(person, delay) {
    setTimeout(() => this.logGreeting(person), delay);
  };
}

如果你想记录this (例如使用私有方法),你可以使用 JSDoc @this

/** @class */
function Person(name) {

  /** This person's name */
  this.name = name;

  /** Greet someone */
  this.greet = function(person) {
    return 'Hey there, '+person.name;
  };

  /** Log a greeting to the browser console */
  this.logGreeting = function(person) {
    privateLogGreeting.call(this, person);
  };

  /** Log a greeting to the browser console after some delay */
  this.logGreetingDelayed = function(person, delay) {
    setTimeout(() => this.logGreeting(person), delay);
  };
}
//Private method
/**
 * @this Person
 * @param {Person} person
 */
function privateLogGreeting(person) {
  console.log(this.greet(person));
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM