我們使用 JSDoc 中的注釋風(fēng)格. 行內(nèi)注釋使用 // 變量 的形式. 另外, 我們也遵循 C++ 代碼注釋風(fēng)格 . 這也就是說你需要:
- 版權(quán)和著作權(quán)的信息,
- 文件注釋中應(yīng)該寫明該文件的基本信息(如, 這段代碼的功能摘要, 如何使用, 與哪些東西相關(guān)), 來告訴那些不熟悉代碼的讀者.
- 類, 函數(shù), 變量和必要的注釋,
- 期望在哪些瀏覽器中執(zhí)行,
- 正確的大小寫, 標(biāo)點和拼寫.
為了避免出現(xiàn)句子片段, 請以合適的大/小寫單詞開頭, 并以合適的標(biāo)點符號結(jié)束這個句子.
現(xiàn)在假設(shè)維護(hù)這段代碼的是一位初學(xué)者. 這可能正好是這樣的!
目前很多編譯器可從 JSDoc 中提取類型信息, 來對代碼進(jìn)行驗證, 刪除和壓縮. 因此, 你很有必要去熟悉正確完整的 JSDoc .
頂層/文件注釋
頂層注釋用于告訴不熟悉這段代碼的讀者這個文件中包含哪些東西. 應(yīng)該提供文件的大體內(nèi)容, 它的作者, 依賴關(guān)系和兼容性信息. 如下:
// Copyright 2009 Google Inc. All Rights Reserved. /** * @fileoverview Description of file, its uses and information * about its dependencies. * @author user@google.com (Firstname Lastname) */
類注釋
每個類的定義都要附帶一份注釋, 描述類的功能和用法. 也需要說明構(gòu)造器參數(shù). 如果該類繼承自其它類, 應(yīng)該使用 @extends
標(biāo)記. 如果該類是對接口的實現(xiàn), 應(yīng)該使用 @implements
標(biāo)記.
/** * Class making something fun and easy. * @param {string} arg1 An argument that makes this more interesting. * @param {Array.<number>} arg2 List of numbers to be processed. * @constructor * @extends {goog.Disposable} */ project.MyClass = function(arg1, arg2) { // ... }; goog.inherits(project.MyClass, goog.Disposable);
方法與函數(shù)的注釋
提供參數(shù)的說明. 使用完整的句子, 并用第三人稱來書寫方法說明.
/** * Converts text to some completely different text. * @param {string} arg1 An argument that makes this more interesting. * @return {string} Some return value. */ project.MyClass.prototype.someMethod = function(arg1) { // ... }; /** * Operates on an instance of MyClass and returns something. * @param {project.MyClass} obj Instance of MyClass which leads to a long * comment that needs to be wrapped to two lines. * @return {boolean} Whether something occured. */ function PR_someMethod(obj) { // ... }
對于一些簡單的, 不帶參數(shù)的 getters, 說明可以忽略.
/** * @return {Element} The element for the component. */ goog.ui.Component.prototype.getElement = function() { return this.element_; };
屬性注釋
也需要對屬性進(jìn)行注釋.
/** * Maximum number of things per pane. * @type {number} */ project.MyClass.prototype.someProperty = 4;
類型轉(zhuǎn)換的注釋
有時, 類型檢查不能很準(zhǔn)確地推斷出表達(dá)式的類型, 所以應(yīng)該給它添加類型標(biāo)記注釋來明確之, 并且必須在表達(dá)式和類型標(biāo)簽外面包裹括號.
/** @type {number} */ (x) (/** @type {number} */ x)
JSDoc 縮進(jìn)
如果你在 @param
, @return
, @supported
, @this
或 @deprecated
中斷行, 需要像在代碼中一樣, 使用4個空格作為一個縮進(jìn)層次.
/** * Illustrates line wrapping for long param/return descriptions. * @param {string} foo This is a param with a description too long to fit in * one line. * @return {number} This returns something that has a description too long to * fit in one line. */ project.MyClass.prototype.method = function(foo) { return 5; };
不要在 @fileoverview
標(biāo)記中進(jìn)行縮進(jìn).
雖然不建議, 但也可對說明文字進(jìn)行適當(dāng)?shù)呐虐鎸R. 不過, 這樣帶來一些負(fù)面影響, 就是當(dāng)你每次修改變量名時, 都得重新排版說明文字以保持和變量名對齊.
/** * This is NOT the preferred indentation method. * @param {string} foo This is a param with a description too long to fit in * one line. * @return {number} This returns something that has a description too long to * fit in one line. */ project.MyClass.prototype.method = function(foo) { return 5; };
枚舉
/** * Enum for tri-state values. * @enum {number} */ project.TriState = { TRUE: 1, FALSE: -1, MAYBE: 0 };
注意一下, 枚舉也具有有效類型, 所以可以當(dāng)成參數(shù)類型來用.
/** * Sets project state. * @param {project.TriState} state New project state. */ project.setState = function(state) { // ... };
Typedefs
有時類型會很復(fù)雜. 比如下面的函數(shù), 接收 Element 參數(shù):
/** * @param {string} tagName * @param {(string|Element|Text|Array.<Element>|Array.<Text>)} contents * @return {Element} */ goog.createElement = function(tagName, contents) { ... };
你可以使用 @typedef
標(biāo)記來定義個常用的類型表達(dá)式.
/** @typedef {(string|Element|Text|Array.<Element>|Array.<Text>)} */ goog.ElementContent; /** * @param {string} tagName * @param {goog.ElementContent} contents * @return {Element} */ goog.createElement = function(tagName, contents) { ... };
JSDoc 標(biāo)記表
標(biāo)記 | 模板 & 例子 | 描述 | 類型檢測支持 |
---|
@param | @param {Type} 變量名 描述 如: /** * Queries a Baz for items. * @param {number} groupNum Subgroup id to query. * @param {string|number|null} term An itemName, * or itemId, or null to search everything. */ goog.Baz.prototype.query = function(groupNum, term) { // ... }; | 給方法, 函數(shù), 構(gòu)造器中的參數(shù)添加說明. | 完全支持. |
@return | @return {Type} 描述 如: /** * @return {string} The hex ID of the last item. */ goog.Baz.prototype.getLastId = function() { // ... return id; }; | 給方法, 函數(shù)的返回值添加說明. 在描述布爾型參數(shù)時, 用 "Whether the component is visible" 這種描述優(yōu)于 "True if the component is visible, false otherwise". 如果函數(shù)沒有返回值, 就不需要添加 @return 標(biāo)記. | 完全支持. |
@author | @author username@google.com (first last) 如: /** * @fileoverview Utilities for handling textareas. * @author kuth@google.com (Uthur Pendragon) */ | 表明文件的作者, 通常僅會在 @fileoverview 注釋中使用到它. | 不需要. |
@see | @see Link 如: /** * Adds a single item, recklessly. * @see #addSafely * @see goog.Collect * @see goog.RecklessAdder#add ... | 給出引用鏈接, 用于進(jìn)一步查看函數(shù)/方法的相關(guān)細(xì)節(jié). | 不需要. |
@fileoverview | @fileoverview 描述 如: /** * @fileoverview Utilities for doing things that require this very long * but not indented comment. * @author kuth@google.com (Uthur Pendragon) */ | 文件通覽. | 不需要. |
@constructor | @constructor 如: /** * A rectangle. * @constructor */ function GM_Rect() { ... } | 指明類中的構(gòu)造器. | 會檢查. 如果省略了, 編譯器將禁止實例化. |
@interface | @interface 如: /** * A shape. * @interface */ function Shape() {}; Shape.prototype.draw = function() {}; /** * A polygon. * @interface * @extends {Shape} */ function Polygon() {}; Polygon.prototype.getSides = function() {}; | 指明這個函數(shù)是一個接口. | 會檢查. 如果實例化一個接口, 編譯器會警告. |
@type | @type Type @type {Type}如: /** * The message hex ID. * @type {string} */ var hexId = hexId; | 標(biāo)識變量, 屬性或表達(dá)式的類型. 大多數(shù)類型是不需要加大括號的, 但為了保持一致, 建議統(tǒng)一加大括號. | 會檢查 |
@extends | @extends Type @extends {Type}如: /** * Immutable empty node list. * @constructor * @extends goog.ds.BasicNodeList */ goog.ds.EmptyNodeList = function() { ... }; | 與 @constructor 一起使用, 用來表明該類是擴展自其它類的. 類型外的大括號可寫可不寫. | 會檢查 |
@implements | @implements Type @implements {Type}如: /** * A shape. * @interface */ function Shape() {}; Shape.prototype.draw = function() {}; /** * @constructor * @implements {Shape} */ function Square() {}; Square.prototype.draw = function() { ... }; | 與 @constructor 一起使用, 用來表明該類實現(xiàn)自一個接口. 類型外的大括號可寫可不寫. | 會檢查. 如果接口不完整, 編譯器會警告. |
@lends | @lends objectName @lends {objectName}如: goog.object.extend( Button.prototype, /** @lends {Button.prototype} */ { isButton: function() { return true; } }); | 表示把對象的鍵看成是其他對象的屬性. 該標(biāo)記只能出現(xiàn)在對象語法中. 注意, 括號中的名稱和其他標(biāo)記中的類型名稱不一樣, 它是一個對象名, 以"借過來"的屬性名命名. 如, @type {Foo} 表示 "Foo 的一個實例", but @lends {Foo} 表示 "Foo 構(gòu)造器". 更多有關(guān)此標(biāo)記的內(nèi)容見 JSDoc Toolkit docs. | 會檢查 |
@private | @private 如: /** * Handlers that are listening to this logger. * @type Array.<Function> * @private */ this.handlers_ = []; | 指明那些以下劃線結(jié)尾的方法和屬性是 私有的. 不推薦使用后綴下劃線, 而應(yīng)改用 @private. | 需要指定標(biāo)志來開啟. |
@protected | @protected 如: /** * Sets the component's root element to the given element. Considered * protected and final. * @param {Element} element Root element for the component. * @protected */ goog.ui.Component.prototype.setElementInternal = function(element) { // ... }; | 指明接下來的方法和屬性是 被保護(hù)的. 被保護(hù)的方法和屬性的命名不需要以下劃線結(jié)尾, 和普通變量名沒區(qū)別. | 需要指定標(biāo)志來開啟. |
@this | @this Type @this {Type}如: pinto.chat.RosterWidget.extern('getRosterElement', /** * Returns the roster widget element. * @this pinto.chat.RosterWidget * @return {Element} */ function() { return this.getWrappedComponent_().getElement(); }); | 指明調(diào)用這個方法時, 需要在哪個上下文中. 當(dāng) this 指向的不是原型方法的函數(shù)時必須使用這個標(biāo)記. | 會檢查 |
@supported | @supported 描述 如: /** * @fileoverview Event Manager * Provides an abstracted interface to the * browsers' event systems. * @supported So far tested in IE6 and FF1.5 */ | 在文件概述中用到, 表明支持哪些瀏覽器. | 不需要. |
@enum | @enum {Type} 如: /** * Enum for tri-state values. * @enum {number} */ project.TriState = { TRUE: 1, FALSE: -1, MAYBE: 0 }; | 用于枚舉類型. | 完全支持. 如果省略, 會認(rèn)為是整型. |
@deprecated | @deprecated 描述 如: /** * Determines whether a node is a field. * @return {boolean} True if the contents of * the element are editable, but the element * itself is not. * @deprecated Use isField(). */ BN_EditUtil.isTopEditableField = function(node) { // ... }; | 告訴其他開發(fā)人員, 此方法, 函數(shù)已經(jīng)過時, 不要再使用. 同時也會給出替代方法或函數(shù). | 不需要 |
@override | @override 如: /** * @return {string} Human-readable representation of project.SubClass. * @override */ project.SubClass.prototype.toString() { // ... }; | 指明子類的方法和屬性是故意隱藏了父類的方法和屬性. 如果子類的方法和屬性沒有自己的文檔, 就會繼承父類的. | 會檢查 |
@inheritDoc | @inheritDoc 如: /** @inheritDoc */ project.SubClass.prototype.toString() { // ... }; | 指明子類的方法和屬性是故意隱藏了父類的方法和屬性, 它們具有相同的文檔. 注意: 使用 @inheritDoc 意味著也同時使用了 @override. | 會檢查 |
@code | {@code ...} 如: /** * Moves to the next position in the selection. * Throws {@code goog.iter.StopIteration} when it * passes the end of the range. * @return {Node} The node at the next position. */ goog.dom.RangeIterator.prototype.next = function() { // ... }; | 說明這是一段代碼, 讓它能在生成的文檔中正確的格式化. | 不適用. |
@license or@preserve | @license 描述 如: /** * @preserve Copyright 2009 SomeThirdParty. * Here is the full license text and copyright * notice for this file. Note that the notice can span several * lines and is only terminated by the closing star and slash: */ | 所有被標(biāo)記為 @license 或 @preserve 的, 會被編譯器保留不做任何修改而直接輸出到最終文擋中. 這個標(biāo)記讓一些重要的信息(如法律許可或版權(quán)信息)原樣保留, 同樣, 文本中的換行也會被保留. | 不需要. |
@noalias | @noalias 如: /** @noalias */ function Range() {} | 在外部文件中使用, 告訴編譯器不要為這個變量或函數(shù)重命名. | 不需要. |
@define | @define {Type} 描述 如: /** @define {boolean} */ var TR_FLAGS_ENABLE_DEBUG = true; /** @define {boolean} */ goog.userAgent.ASSUME_IE = false; | 表示該變量可在編譯時被編譯器重新賦值. 在上面例子中, BUILD 文件中指定了 --define='goog.userAgent.ASSUME_IE=true' 這個編譯之后, 常量 goog.userAgent.ASSUME_IE 將被全部直接替換為 true. | 不需要. |
@export | @export 如: /** @export */ foo.MyPublicClass.prototype.myPublicMethod = function() { // ... }; | 上面的例子代碼, 當(dāng)編譯器運行時指定 --generate_exports 標(biāo)志, 會生成下面的代碼: goog.exportSymbol('foo.MyPublicClass.prototype.myPublicMethod', foo.MyPublicClass.prototype.myPublicMethod); 編譯后, 將源代碼中的名字原樣導(dǎo)出. 使用 @export 標(biāo)記時, 應(yīng)該 - 包含 //javascript/closure/base.js, 或者
- 在代碼庫中自定義 goog.exportSymbol 和 goog.exportProperty 兩個方法, 并保證有相同的調(diào)用方式.
| 不需要. |
@const | @const 如: /** @const */ var MY_BEER = 'stout'; /** * My namespace's favorite kind of beer. * @const * @type {string} */ mynamespace.MY_BEER = 'stout'; /** @const */ MyClass.MY_BEER = 'stout'; | 聲明變量為只讀, 直接寫在一行上. 如果其他代碼中重寫該變量值, 編譯器會警告. 常量應(yīng)全部用大寫字符, 不過使用這個標(biāo)記, 可以幫你消除命名上依賴. 雖然 jsdoc.org 上列出的 @final 標(biāo)記作用等價于 @const , 但不建議使用. @const 與 JS1.5 中的 const 關(guān)鍵字一致. 注意, 編譯器不禁止修改常量對象的屬性(這與 C++ 中的常量定義不一樣). 如果可以準(zhǔn)確推測出常量類型的話, 那么類型申明可以忽略. 如果指定了類型, 應(yīng)該也寫在同一行上. 變量的額外注釋可寫可不寫. | 支持. |
@nosideeffects | @nosideeffects 如: /** @nosideeffects */ function noSideEffectsFn1() { // ... }; /** @nosideeffects */ var noSideEffectsFn2 = function() { // ... }; /** @nosideeffects */ a.prototype.noSideEffectsFn3 = function() { // ... }; | 用于對函數(shù)或構(gòu)造器聲明, 說明調(diào)用此函數(shù)不會有副作用. 編譯器遇到此標(biāo)記時, 如果調(diào)用函數(shù)的返回值沒有其他地方使用到, 則會將這個函數(shù)整個刪除. | 不需要檢查. |
@typedef | @typedef 如: /** @typedef {(string|number)} */ goog.NumberLike; /** @param {goog.NumberLike} x A number or a string. */ goog.readNumber = function(x) { ... } | 這個標(biāo)記用于給一個復(fù)雜的類型取一個別名. | 會檢查 |
@externs | @externs 如: /** * @fileoverview This is an externs file. * @externs */ var document; | 指明一個外部文件. | 不會檢查 |
在第三方代碼中, 你還會見到其他一些 JSDoc 標(biāo)記. 這些標(biāo)記在 JSDoc Toolkit Tag Reference 都有介紹到, 但在 Google 的代碼中, 目前不推薦使用. 你可以認(rèn)為這些是將來會用到的 "保留" 名. 它們包含:
- @augments
- @argument
- @borrows
- @class
- @constant
- @constructs
- @default
- @event
- @example
- @field
- @function
- @ignore
- @inner
- @link
- @memberOf
- @name
- @namespace
- @property
- @public
- @requires
- @returns
- @since
- @static
- @version
JSDoc 中的 HTML
類似于 JavaDoc, JSDoc 支持許多 HTML 標(biāo)簽, 如 <code>, <pre>, <tt>, <strong>, <ul>, <ol>, <li>, <a>, 等等.
這就是說 JSDoc 不會完全依照純文本中書寫的格式. 所以, 不要在 JSDoc 中, 使用空白字符來做格式化:
/** * Computes weight based on three factors: * items sent * items received * last timestamp */
上面的注釋, 出來的結(jié)果是:
Computes weight based on three factors: items sent items received items received
應(yīng)該這樣寫:
/** * Computes weight based on three factors: * <ul> * <li>items sent * <li>items received * <li>last timestamp * </ul> */
另外, 也不要包含任何 HTML 或類 HTML 標(biāo)簽, 除非你就想讓它們解析成 HTML 標(biāo)簽.
/** * Changes <b> tags to <span> tags. */
出來的結(jié)果是:
Changes tags to tags.
另外, 也應(yīng)該在源代碼文件中讓其他人更可讀, 所以不要過于使用 HTML 標(biāo)簽:
/** * Changes <b> tags to <span> tags. */
上面的代碼中, 其他人就很難知道你想干嘛, 直接改成下面的樣子就清楚多了:
/** * Changes 'b' tags to 'span' tags. */