這是 常見的開發問題:您編寫了 JavaScript 程式碼供他人使用,並需要其 API 的美觀 HTML 文件。在 JavaScript 世界中,用於產生 API 文件的實際標準工具是 JSDoc。[23] 它仿照其 Java 類比 JavaDoc 建模。
JSDoc 使用帶有 /** */
註解的 JavaScript 程式碼(以星號開頭的正常區塊註解),並為其產生 HTML 文件。例如,給定以下程式碼:
/** @namespace */
var
util
=
{
/**
* Repeat <tt>str</tt> several times.
* @param {string} str The string to repeat.
* @param {number} [times=1] How many times to repeat the string.
* @returns {string}
*/
repeat
:
function
(
str
,
times
)
{
if
(
times
===
undefined
||
times
<
1
)
{
times
=
1
;
}
return
new
Array
(
times
+
1
).
join
(
str
);
}
};
產生的 HTML 在網頁瀏覽器中看起來如 圖 29-1 所示。
JSDoc 網站上的 自述檔 說明如何安裝和呼叫此工具。
JSDoc 旨在記錄 實體(函式、方法、建構函式等)。這是透過在實體之前加上以 /**
開頭的註解來達成。
讓我們檢閱 一開始顯示的註解:
/**
* Repeat <tt>str</tt> several times.
* @param {string} str The string to repeat.
* @param {number} [times=1] How many times to repeat the string.
* @returns {string}
*/
這展示了部分 JSDoc 語法,它包含以下部分
/**
開頭此類註解的錯覺。
@param
是前述程式碼中的範例。 <tt>
會以等寬字型顯示一個字詞。 @param {string} name
@param {string|number} idCode
@param {string[]} names
在 JSDoc 註解中,所謂的 名稱路徑 用於參照實體。此類路徑的語法如下
myFunction MyClass MyClass.staticMember MyClass#instanceMember
類別 通常由建構函式(實作)。例如,靜態成員是建構函式的屬性。JSDoc 對 實例成員 有廣泛的定義。其意指可透過實例存取的一切內容。因此,實例成員包括實例屬性和原型屬性。
實體的類型 為基本類型或類別。前者的名稱總是從小寫字母開始;後者的名稱總是從大寫字母開始。換句話說,基本類型的名稱為 boolean
、number
和 string
,就像 typeof
營運子傳回的結果一樣。這樣一來,您就不會將字串(基本類型)與建構函式 String
(物件)的實例混淆。
以下是基本元資料標籤:
@fileOverview 說明
標記說明整個檔案的 JSDoc 註解。例如
/**
* @fileOverview Various tool functions.
* @author <a href="mailto:jd@example.com">John Doe</a>
* @version 3.1.2
*/
@author
@deprecated
@example
包含說明如何使用所提供實體的程式碼範例
/**
* @example
* var str = 'abc';
* console.log(repeat(str, 3)); // abcabcabc
*/
連結的基本標籤如下
@see
指向相關資源
/**
* @see MyConstructor#myMethod
* @see The <a href="http://example.com">Example Project</a>.
*/
{@link ...}
@see
,但可用於其他標籤中。
@requires resourceDescription
版本標籤包括以下內容
@version versionNumber
指出記錄實體的版本。例如
@version 10.3.1
@since versionNumber
指出記錄實體自哪個版本開始提供。例如
@since 10.2.0
對於函式和方法,您可以記錄參數、傳回值和它們可能會引發的例外狀況:
@param {paramType} paramName 說明
說明名稱為 paramName
的 參數。類型和說明為選用。以下是一些範例:
@param str The string to repeat. @param {string} str @param {string} str The string to repeat.
進階功能
選用參數
@param {number} [times] The number of times is optional.
具有預設值的選用參數
@param {number} [times=1] The number of times is optional.
@returns {returnType} 說明
@throws {exceptionType} description
有 兩種提供參數和回傳值類型資訊的方法。首先,您可以將類型註解新增至 @param
和 @returns
:
/**
* @param {String} name
* @returns {Object}
*/
function
getPerson
(
name
)
{
}
其次,您可以內嵌類型資訊
function
getPerson
(
/**String*/
name
)
/**Object*/
{
}
下列標籤 用於文件化變數、參數和實例屬性:
@type {typeName}
/** @type {number} */
var
carCounter
=
0
;
此標籤也可用于文件化函數的回傳類型,但 @returns
在此情況下較佳。
@constant
表示文件化變數具有常數值的旗標。
/** @constant */
var
FORD
=
'Ford'
;
@property {propType} propKey description
在建構函數註解中文件化 實例屬性。例如:
/**
* @constructor
* @property {string} name The name of the person.
*/
function
Person
(
name
)
{
this
.
name
=
name
;
}
或者,實例屬性可以如下文件化
/**
* @class
*/
function
Person
(
name
)
{
/**
* The name of the person.
* @type {string}
*/
this
.
name
=
name
;
}
使用哪一種樣式取決於個人喜好。
@default defaultValue
/** @constructor */
function
Page
(
title
)
{
/**
* @default 'Untitled'
*/
this
.
title
=
title
||
'Untitled'
;
}
JSDoc 區分 類別和建構函數。前者概念較像類型,而建構函數是實作類別的方法之一。JavaScript 定義類別的內建方法有限,因此有許多 API 可協助執行此任務。這些 API 差異很大,因此您必須協助 JSDoc 找出發生了什麼事。下列標籤可讓您執行此操作:
@constructor
@class
@class
是 @constructor
的同義詞。
@constructs
@lends namePath
指定下列物件文字對應哪個類別。有兩種對應方式。
@lends Person#
:物件文字對應 Person
的實例成員。
@lends Person
:物件文字對應 Person
的靜態成員。
@memberof parentNamePath
@lends MyClass#
,其效果等同於使用 @memberof MyClass#
標記該文字的每個屬性。
定義類別最常見的方式有:透過建構函式、透過物件文字,以及透過具有 @constructs
方法的物件文字。
若要透過建構函式定義類別,您必須標記建構函式;否則,它不會被記錄為類別。 光靠大寫並不足以標記函式為建構函式:
/**
* A class for managing persons.
* @constructor
*/
function
Person
(
name
)
{
}
若要透過物件文字定義類別,您需要兩個標記。首先,您需要告訴 JSDoc 給定的變數包含類別。其次,您需要標記物件文字為定義類別。您可以透過 @lends
標籤執行後者:
/**
* A class for managing persons.
* @class
*/
var
Person
=
makeClass
(
/** @lends Person# */
{
say
:
function
(
message
)
{
return
'This person says: '
+
message
;
}
}
);
如果物件文字具有 @constructs
方法,您需要告訴 JSDoc,以便它可以找到實例屬性的文件。類別的文件會移至該方法:
var
Person
=
makeClass
(
/** @lends Person# */
{
/**
* A class for managing persons.
* @constructs
*/
initialize
:
function
(
name
)
{
this
.
name
=
name
;
},
say
:
function
(
message
)
{
return
this
.
name
+
' says: '
+
message
;
}
}
);
如果您省略 @lends
,您必須指定方法所屬的類別
var
Person
=
makeClass
({
/**
* A class for managing persons.
* @constructs Person
*/
initialize
:
function
(
name
)
{
this
.
name
=
name
;
},
/** @memberof Person# */
say
:
function
(
message
)
{
return
this
.
name
+
' says: '
+
message
;
}
}
);
JavaScript 沒有內建的子類化支援。當您在程式碼中進行子類化(不論是手動或透過函式庫),您必須告訴 JSDoc 正在發生什麼事:
@extends namePath
表示已記錄的類別是另一個類別的子類別。例如
/**
* @constructor
* @extends Person
*/
function
Programmer
(
name
)
{
Person
.
call
(
this
,
name
);
...
}
// Remaining code for subclassing omitted