Documenting JavaScript with jsdoc3

JavaScript is an extremely dynamic language which allows it to be applied in a variety of interesting ways. Some prefer to take the structured approach whilst others prefer an object-oriented approach using the prototype object or a library that offers a more classical approach. This diversity makes docblock type documentation seem impossible… but it isn’t!!

Thanks to jsdoc3 this task is made significantly simpler. It’s rich selection of tags makes it possible to document even the most abstract concepts that JavaScript permits. It is also extremely easy to create plugins and custom templates. Jsdoc is a command-line tool that works on any platform that supports Java. See project pages for information about usage.

A Few Examples

Here are some examples of how jsdoc3 can be applied:

Function

/**
 * Do something really neat
 */
function foo() {
}
 
/**
  * Do something really neat with parameters - last is optional!
  * @param {string|number} lookup Name or ID of user
  * @param {string} type Type of records to lookup
  * @param {string} [count] Maximum count of entries to retrieve
  * @returns List of records
  */
function getRecords(lookup, type, count) {
}

Note that the other variant of functions can be documented in the same way:

/**
 * Do something really neat
 */
foo = function() {
};

Namespace

Straightforward namespaces can be documented with the following:

/**
 * Root namespace
 * @namespace root
 */
root = {
   /**
    * Do something really neat
    */
   foo: function() {
   }
};
 
/**
 * Nested namespace
 * @namespace root.nested
 */
root.nested = {
   /**
    * Do something else that is really neat
    */
   bar: function() {
   }
};

Namespaces can still be documented when a more abstract mechanism is used. @lends allows members to be added to an existing namespace:

/**
 * Root namespace
 * @namespace root
 */
$namespace('root', /** @lends root **/ {
   /**
    * Do something really neat
    */
   foo: function() {
   }
});
 
/**
 * Nested namespace
 * @namespace root.nested
 */
$namespace('root.nested', /** @lends root.nested **/ {
   /**
    * Do something else that is really neat
    */
   bar: function() {
   }
});

Class (with prototype object)

/**
 * Base class of a game entity
 * @class Entity
 */
Entity = function() {
};
 
/**
 * Render entity
 * @param {CanvasRenderingContext2D} dc Device context
 */
Entity.prototype.render = function(dc) {
   // Instance method!
};
 
/**
 * Get new instance of entity
 * @param {string} type Type of entity to instantiate
 * @returns {@link Entity}
 */
Entity.getInstance: function(type) {
   // Static method!
};

Classes (with classical approach)

/**
 * Base class of a game entity
 * @class Entity
 */
$class('Entity', /** @lends Entity# **/ {
   /**
   * Render entity
   * @param {CanvasRenderingContext2D} dc Device context
   */
   render: function(dc) {
      // Instance method!
   }
}, /** @lends Entity **/ {
   /**
    * Get new instance of entity
    * @param {string} type Type of entity to instantiate
    * @returns {@link Entity}
    */
   getInstance: function(type) {
      // Static method!
   }
});
/**
 * Ball entity
 * @class Ball
 * @extends Entity
 */
$class('Ball', 'Entity', /** @lends Ball# **/ {
   /**
    * Force ball to bounce
    */
   bounce: function() {
      // Instance method!
   }
});