It is a common development problem: you have written JavaScript code that is to be used by others and need a nice-looking HTML documentation of its API. The de facto standard tool in the JavaScript world for generating API documentation is JSDoc.[23] It is modeled after its Java analog, JavaDoc.
JSDoc takes JavaScript code with /** */
comments (normal block comments that start with an asterisk) and produces HTML documentation for it. For example, given the following code:
/** @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
);
}
};
the generated HTML looks as shown in Figure 29-1 in a web browser.
The Readme on the JSDoc website explains how to install and call this tool.
JSDoc is all about documenting entities (functions, methods, constructors, etc.). That is achieved via comments that precede the entities and start with /**
.
Let’s review the comment shown at the beginning:
/**
* 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}
*/
This demonstrates some of the JSDoc syntax, which consists of the following pieces:
/**
starts such a comment.
@param
is an example in the preceding code.
<tt>
displays a word in a monospaced font.
You can document the type of an entity via a type name in braces. Variations include:
@param {string} name
@param {string|number} idCode
@param {string[]} names
Inside JSDoc comments, so-called namepaths are used to refer to entities. The syntax of such paths is as follows:
myFunction MyClass MyClass.staticMember MyClass#instanceMember
Classes are usually (implemented by) constructors. Static members are, for example, properties of constructors. JSDoc has a broad definition of instance member. It means everything that can be accessed via an instance. Therefore, instance members include instance properties and prototype properties.
The types of entities are either primitive types or classes. The names of the former always start with lowercase letters; the names of the latter always start with uppercase letters. In other words, the type names of primitives are boolean
, number
, and string
, just like the results returned by the typeof
operator. That way, you cannot confuse strings (primitives) with instances of the constructor String
(objects).
Following are the basic metadata tags:
@fileOverview description
Marks a JSDoc comment that describes the whole file. For example:
/**
* @fileOverview Various tool functions.
* @author <a href="mailto:jd@example.com">John Doe</a>
* @version 3.1.2
*/
@author
@deprecated
@example
Contains a code example illustrating how the given entity should be used:
/**
* @example
* var str = 'abc';
* console.log(repeat(str, 3)); // abcabcabc
*/
Basic tags for linking are as follows:
@see
Points to a related resource:
/**
* @see MyConstructor#myMethod
* @see The <a href="http://example.com">Example Project</a>.
*/
{@link ...}
@see
, but can be used inside other tags.
@requires resourceDescription
Versioning tags include the following:
@version versionNumber
Indicates the version of the documented entity. For example:
@version 10.3.1
@since versionNumber
Indicates since which version the documented entity has been available. For example:
@since 10.2.0
For functions and methods, you can document parameters, return values, and exceptions they may throw:
@param {paramType} paramName description
Describes the parameter whose name is paramName
. Type and description are optional. Here are some examples:
@param str The string to repeat. @param {string} str @param {string} str The string to repeat.
Advanced features:
Optional parameter:
@param {number} [times] The number of times is optional.
Optional parameter with default value:
@param {number} [times=1] The number of times is optional.
@returns {returnType} description
@throws {exceptionType} description
/**
* @param {String} name
* @returns {Object}
*/
function
getPerson
(
name
)
{
}
Second, you can inline the type information:
function
getPerson
(
/**String*/
name
)
/**Object*/
{
}
The following tags are used for documenting variables, parameters, and instance properties:
@type {typeName}
What type does the documented variable have? For example:
/** @type {number} */
var
carCounter
=
0
;
This tag can also be used to document the return type of functions, but @returns
is preferable in this case.
@constant
A flag that indicates that the documented variable has a constant value.
/** @constant */
var
FORD
=
'Ford'
;
@property {propType} propKey description
Document an instance property in the constructor comment. For example:
/**
* @constructor
* @property {string} name The name of the person.
*/
function
Person
(
name
)
{
this
.
name
=
name
;
}
Alternatively, instance properties can be documented as follows:
/**
* @class
*/
function
Person
(
name
)
{
/**
* The name of the person.
* @type {string}
*/
this
.
name
=
name
;
}
Which one of those styles to use is a matter of personal preference.
@default defaultValue
What is the default value of a parameter or instance property? For example:
/** @constructor */
function
Page
(
title
)
{
/**
* @default 'Untitled'
*/
this
.
title
=
title
||
'Untitled'
;
}
JSDoc distinguishes between classes and constructors. The former concept is more like a type, while a constructor is one way of implementing a class. JavaScript’s built-in means for defining classes are limited, which is why there are many APIs that help with this task. These APIs differ, often radically, so you have to help JSDoc with figuring out what is going on. The following tags let you do that:
@constructor
@class
@class
is a synonym for @constructor
.
@constructs
@lends namePath
Specifies to which class the following object literal contributes. There are two ways of contributing.
@lends Person#
: The object literal contributes instance members to Person
.
@lends Person
: The object literal contributes static members to Person
.
@memberof parentNamePath
@lends MyClass#
, applied to an object literal, has the same effect as marking each property of that literal with @memberof MyClass#
.
The most common ways of defining a class are: via a constructor function, via an object literal, and via an object literal that has an @constructs
method.
To define a class via a constructor function, you must mark the constructor function; otherwise, it will not be documented as a class. Capitalization alone does not mark a function as a constructor:
/**
* A class for managing persons.
* @constructor
*/
function
Person
(
name
)
{
}
To define a class via an object literal, you need two markers. First, you need to tell JSDoc that a given variable holds a class. Second, you need to mark an object literal as defining a class. You do the latter via the @lends
tag:
/**
* A class for managing persons.
* @class
*/
var
Person
=
makeClass
(
/** @lends Person# */
{
say
:
function
(
message
)
{
return
'This person says: '
+
message
;
}
}
);
If an object literal has an @constructs
method, you need to tell JSDoc about it, so that it can find the documentation for the instance properties. The documentation of the class moves to that method:
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
;
}
}
);
If you omit the @lends
, you must specify which class the methods belong to:
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 has no built-in support for subclassing. When you subclass in your code (be it manually, be it via a library), you have to tell JSDoc what is going on:
@extends namePath
Indicates that the documented class is the subclass of another one. For example:
/**
* @constructor
* @extends Person
*/
function
Programmer
(
name
)
{
Person
.
call
(
this
,
name
);
...
}
// Remaining code for subclassing omitted
All of these tags are documented at the JSDoc website: