Es ist ein häufiges Entwicklungsproblem: Sie haben JavaScript-Code geschrieben, der von anderen verwendet werden soll, und benötigen eine ansprechend aussehende HTML-Dokumentation seiner API. Das De-facto-Standardwerkzeug in der JavaScript-Welt für die Generierung von API-Dokumentationen ist JSDoc.[23] Es ist seinem Java-Analogon, JavaDoc, nachempfunden.
JSDoc nimmt JavaScript-Code mit /** */-Kommentaren (normale Blockkommentare, die mit einem Sternchen beginnen) und erzeugt daraus eine HTML-Dokumentation. Zum Beispiel, gegeben den folgenden Code:
/** @namespace */varutil={/*** 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;}returnnewArray(times+1).join(str);}};
sieht die generierte HTML-Ausgabe wie in Abbildung 29-1 in einem Webbrowser aus.
Das Readme auf der JSDoc-Website erklärt, wie dieses Werkzeug installiert und aufgerufen wird.
Bei JSDoc geht es darum, Entitäten (Funktionen, Methoden, Konstruktoren usw.) zu dokumentieren. Dies geschieht über Kommentare, die den Entitäten vorangehen und mit /** beginnen.
Betrachten wir den am Anfang gezeigten Kommentar:
/*** 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}*/
Dies demonstriert einige der JSDoc-Syntax, die aus den folgenden Teilen besteht:
/** einen solchen Kommentar beginnt.@param ist ein Beispiel im vorherigen Code.<tt> ein Wort in einer Monospace-Schrift an.Sie können den Typ einer Entität über einen Typnamen in geschweiften Klammern dokumentieren. Variationen sind:
@param {string} name@param {string|number} idCode@param {string[]} namesInnerhalb von JSDoc-Kommentaren werden sogenannte Name-Pfade verwendet, um auf Entitäten zu verweisen. Die Syntax solcher Pfade ist wie folgt:
myFunction MyClass MyClass.staticMember MyClass#instanceMember
Klassen sind in der Regel (implementiert durch) Konstruktoren. Statische Mitglieder sind zum Beispiel Eigenschaften von Konstruktoren. JSDoc hat eine breite Definition von Instanzmitglied. Es bedeutet alles, was über eine Instanz zugänglich ist. Daher umfassen Instanzmitglieder Instanzeigenschaften und Prototyp-Eigenschaften.
Die Typen von Entitäten sind entweder primitive Typen oder Klassen. Die Namen der ersteren beginnen immer mit Kleinbuchstaben; die Namen der letzteren beginnen immer mit Großbuchstaben. Mit anderen Worten, die Typnamen von Primitiven sind boolean, number und string, genau wie die Ergebnisse des typeof-Operators. So können Sie Strings (Primitive) nicht mit Instanzen des Konstruktors String (Objekte) verwechseln.
Folgend sind die grundlegenden Metadaten-Tags:
@fileOverview Beschreibung
Kennzeichnet einen JSDoc-Kommentar, der die gesamte Datei beschreibt. Zum Beispiel:
/*** @fileOverview Various tool functions.* @author <a href="mailto:jd@example.com">John Doe</a>* @version 3.1.2*/
@author
@deprecated
@example
Enthält ein Codebeispiel, das veranschaulicht, wie die gegebene Entität verwendet werden soll.
/*** @example* var str = 'abc';* console.log(repeat(str, 3)); // abcabcabc*/
Grundlegende Tags für Verknüpfungen sind wie folgt:
@see
Verweist auf eine verwandte Ressource.
/*** @see MyConstructor#myMethod* @see The <a href="http://example.com">Example Project</a>.*/
{@link ...}
@see, kann aber innerhalb anderer Tags verwendet werden.@requires resourceDescription
Versions-Tags umfassen die folgenden:
@version versionNumber
Gibt die Version der dokumentierten Entität an. Zum Beispiel:
@version 10.3.1
@since versionNumber
Gibt an, seit welcher Version die dokumentierte Entität verfügbar ist. Zum Beispiel:
@since 10.2.0
Für Funktionen und Methoden können Sie Parameter, Rückgabewerte und Ausnahmen dokumentieren, die sie auslösen können:
@param {paramType} paramName Beschreibung
Beschreibt den Parameter, dessen Name paramName ist. Typ und Beschreibung sind optional. Hier sind einige Beispiele:
@param str The string to repeat.
@param {string} str
@param {string} str The string to repeat.Fortgeschrittene Funktionen
Optionaler Parameter
@param {number} [times] The number of times is optional.Optionaler Parameter mit Standardwert
@param {number} [times=1] The number of times is optional.@returns {returnType} Beschreibung
@throws {exceptionType} Beschreibung
/*** @param {String} name* @returns {Object}*/functiongetPerson(name){}
Zweitens können Sie die Typinformationen inline einfügen:
functiongetPerson(/**String*/name)/**Object*/{}
Die folgenden Tags werden zur Dokumentation von Variablen, Parametern und Instanzeigenschaften verwendet:
@type {typeName}
Welchen Typ hat die dokumentierte Variable? Zum Beispiel:
/** @type {number} */varcarCounter=0;
Dieser Tag kann auch verwendet werden, um den Rückgabetyp von Funktionen zu dokumentieren, aber @returns ist in diesem Fall vorzuziehen.
@constant
Eine Flagge, die angibt, dass die dokumentierte Variable einen konstanten Wert hat.
/** @constant */varFORD='Ford';
@property {propType} propKey Beschreibung
Dokumentieren Sie eine Instanzeigenschaft im Konstruktor-Kommentar. Zum Beispiel:
/*** @constructor* @property {string} name The name of the person.*/functionPerson(name){this.name=name;}
Alternativ können Instanzeigenschaften wie folgt dokumentiert werden:
/*** @class*/functionPerson(name){/*** The name of the person.* @type {string}*/this.name=name;}
Welcher dieser Stile verwendet wird, ist eine Frage der persönlichen Vorliebe.
@default defaultValue
Was ist der Standardwert eines Parameters oder einer Instanzeigenschaft? Zum Beispiel:
/** @constructor */functionPage(title){/*** @default 'Untitled'*/this.title=title||'Untitled';}
JSDoc unterscheidet zwischen Klassen und Konstruktoren. Das erstere Konzept ist eher ein Typ, während ein Konstruktor eine Möglichkeit ist, eine Klasse zu implementieren. Die integrierten Mittel von JavaScript zur Definition von Klassen sind begrenzt, weshalb es viele APIs gibt, die bei dieser Aufgabe helfen. Diese APIs unterscheiden sich oft radikal, sodass Sie JSDoc helfen müssen, herauszufinden, was vor sich geht. Die folgenden Tags ermöglichen Ihnen dies:
@constructor
@class
@class ein Synonym für @constructor.@constructs
@lends namePath
Gibt an, zu welcher Klasse das folgende Objektliteral beiträgt. Es gibt zwei Möglichkeiten, beizutragen.
@lends Person#: Das Objektliteral trägt Instanzmitglieder zu Person bei.@lends Person: Das Objektliteral trägt statische Mitglieder zu Person bei.@memberof parentNamePath
@lends MyClass#, angewendet auf ein Objektliteral, hat die gleiche Wirkung wie das Markieren jeder Eigenschaft dieses Literals mit @memberof MyClass#.Die gängigsten Arten, eine Klasse zu definieren, sind: über eine Konstruktorfunktion, über ein Objektliteral und über ein Objektliteral mit einer @constructs-Methode.
Um eine Klasse über eine Konstruktorfunktion zu definieren, müssen Sie die Konstruktorfunktion markieren; andernfalls wird sie nicht als Klasse dokumentiert. Allein die Großschreibung markiert eine Funktion nicht als Konstruktor:
/*** A class for managing persons.* @constructor*/functionPerson(name){}
Um eine Klasse über ein Objektliteral zu definieren, benötigen Sie zwei Marker. Erstens müssen Sie JSDoc mitteilen, dass eine gegebene Variable eine Klasse enthält. Zweitens müssen Sie ein Objektliteral als definierend für eine Klasse markieren. Dies tun Sie über das @lends-Tag:
/*** A class for managing persons.* @class*/varPerson=makeClass(/** @lends Person# */{say:function(message){return'This person says: '+message;}});
Wenn ein Objektliteral eine @constructs-Methode hat, müssen Sie JSDoc darüber informieren, damit es die Dokumentation für die Instanzeigenschaften finden kann. Die Dokumentation der Klasse wird in diese Methode verschoben:
varPerson=makeClass(/** @lends Person# */{/*** A class for managing persons.* @constructs*/initialize:function(name){this.name=name;},say:function(message){returnthis.name+' says: '+message;}});
Wenn Sie das @lends weglassen, müssen Sie angeben, zu welcher Klasse die Methoden gehören:
varPerson=makeClass({/*** A class for managing persons.* @constructs Person*/initialize:function(name){this.name=name;},/** @memberof Person# */say:function(message){returnthis.name+' says: '+message;}});
JavaScript hat keine integrierte Unterstützung für Unterklassenbildung. Wenn Sie in Ihrem Code Unterklassen bilden (sei es manuell, sei es über eine Bibliothek), müssen Sie JSDoc mitteilen, was vor sich geht:
@extends namePath
Gibt an, dass die dokumentierte Klasse die Unterklasse einer anderen ist. Zum Beispiel:
/*** @constructor* @extends Person*/functionProgrammer(name){Person.call(this,name);...}// Remaining code for subclassing omitted
Alle diese Tags sind auf der JSDoc-Website dokumentiert.
[23] Die JSDoc-Website ist die Hauptquelle dieses Kapitels; einige Beispiele sind von dort übernommen.