JavaScript 代码风格指南

这份指南列出了编写 JavaScript 时需要遵守的规范, 指明哪些应该提倡, 哪些应该避免.
本文基于 google 的规范翻译整理(JavaScript 是许多 Google 开源项目使用的主要客户端脚本语言).

(4)

JavaScript 代码风格规范(3)

注释

使用 JSDoc.

在精神上, 我们遵循 C++ 注释风格的指导.

所有文件, 类, 方法和属性都应该通过合适的标签类型说明使用 JSDoc 进行注释. 除非从属性, 方法和参数的命名中可以清晰地判断其用途, 否则在注释中应当包含对属性, 方法, 方法参数和方法返回值的文字描述.

行内注释应当使用 //.

推荐在注释中使用完整的句子, 但不做严格要求. 完整句子应当正确使用大小写和标点符号.

注释语法

JSDoc 的语法基于 JavaDoc. 有许多工具可以从 JSDoc 注释中提取元数据来执行代码校验和优化. 这些注释必须遵循正确的格式.

1
2
3
4
5
/**
* JSDoc 的注释应当以斜划线和两个星号打头.
* 行内标签应该放在闭合的花括号中, 就像这样: {@code this}.
* @desc 块级标签应当总是另起新行.
*/

JSDoc 缩进

如果你需要对一个块级标签折行, 你应当就像视其为代码块那样缩进 4 格.

1
2
3
4
5
6
7
8
9
10
/**
* 长参数和返回值描述的折行处理示例.
* @param {string} foo 这是某个参数的描述, 由于太长太长太长太长太长太长太长以至于一行内
* 有点放不下.
* @return {number} 这是某个返回值的描述, 由于太长太长太长太长太长太长太长以至于一行内
* 有点放不下.
*/

project.MyClass.prototype.method = function(foo) {
return 5;
};

你不应该缩进 @fileoverview 命令. 你不必缩进 @desc 命令.

即使并不推荐, 但对齐缩进的方式也可以接受.

1
2
3
4
5
6
7
8
9
10
/**
* 并不推荐的缩进方式..
* @param {string} foo 这是某个参数的描述, 由于太长太长太长太长太长太长太长以至于一行内
* 有点放不下.
* @return {number} 这是某个返回值的描述, 由于太长太长太长太长太长太长太长以至于一行内
* 有点放不下.
*/

project.MyClass.prototype.method = function(foo) {
return 5;
};

JSDoc 中的 HTML

类似 JavaDoc, JSDoc 也支持许多 HTML 标签, 诸如 <code>, <pre>, <tt>, <strong>, <ul>, <ol>, <li>, <a> 等等.

这意味着最好不要对纯文本格式化, 不要依赖用空格来格式化 JSDoc:

不要像这样写:

1
2
3
4
5
6
/**
* Computes weight based on three factors:
* items sent
* items received
* last timestamp
*/

输出后它会这样显示:

1
Computes weight based on three factors: items sent items received last timestamp

应该这样写:

1
2
3
4
5
6
7
8
/**
* Computes weight based on three factors:
* <ul>
* <li>items sent
* <li>items received
* <li>last timestamp
* </ul>
*/

如何书写排版优美的文档注释可以参看这篇文章: JSDoc 风格指南.

顶级/文件级注释

版权提示和作者信息是可选的.
无论文件是否包含超过一个类的定义, 一般都推荐加上文件概述.
顶级注释主要面向不熟悉代码的读者, 让他们大致了解文件内代码的用途.
因此注释中应当提供文件内容的描述, 依赖关系或者兼容信息.
下面是一个例子:

1
2
3
4
/**
* @fileoverview Description of file, its uses and information
* about its dependencies.
*/

类注释

类的文档注释应当包含一份描述信息和定义构造函数的类型标签.

1
2
3
4
5
6
7
8
9
10
11
/**
* 类让事情变得简单又有趣.
* @param {string} arg1 让它变得更有趣的参数.
* @param {Array.<number>} arg2 待处理的数字列表.
* @constructor
* @extends {goog.Disposable}
*/

project.MyClass = function(arg1, arg2) {
// ...
};
goog.inherits(project.MyClass, goog.Disposable);

方法和函数注释

应当包含参数和返回值类型的文档注释. 如果从参数或者返回值类型描述中明显能看出方法的作用, 那么可以省略对方法的描述. 方法描述应该使用第三人称的陈述句来开头.

1
2
3
4
5
6
7
8
9
/**
* 对 MyClass 的一个实例进行操作并返回了一些东西.
* @param {project.MyClass} obj MyClass 的实例, 有个老长老长老长的注释, 长到需要
* 放到拆成两行来显示.
* @return {boolean} 判断某些事情是否发生.
*/

function PR_someMethod(obj) {
// ...
}

属性注释

1
2
3
4
5
6
7
8
/** @constructor */
project.MyClass = function() {
/**
* Maximum number of things per pane.
* @type {number}
*/

this.someProperty = 4;
}

JSDoc 标签参考

参见下表:

JSDoc 标签

你还可以在第三方代码中看到许多其他类型的 JSDoc 注解. 整个注解可以在 JSDoc 工具箱标签索引中查询到, 但并不鼓励用于 Google 项目中. 你可以视这些注解为保留名, 可能会在将来投入使用. 它们包括:

  • @augments
  • @argument
  • @borrows
  • @class
  • @constant
  • @constructs
  • @default
  • @event
  • @example
  • @field
  • @function
  • @ignore
  • @inner
  • @link
  • @memberOf
  • @name
  • @namespace
  • @property
  • @public
  • @requires
  • @returns
  • @since
  • @static
  • @version

使用 goog.provide 提供依赖项

只引入最顶级的符号.

一个类定义的所有成员都应处于同一文件中. 因此, 在包含多个定义在同一类中的复数成员的文件中, 只应该引入最顶级的符号(例如枚举类型和内部类等).

应该这样:

1
goog.provide('namespace.MyClass');

不要这样:

1
2
3
4
5
6
7
8
9
10
11
goog.provide('namespace.MyClass');
goog.provide('namespace.MyClass.Enum');
goog.provide('namespace.MyClass.InnerClass');
goog.provide('namespace.MyClass.TypeDef');
goog.provide('namespace.MyClass.CONSTANT');
goog.provide('namespace.MyClass.staticMethod');
Members on namespaces may also be provided:

goog.provide('foo.bar');
goog.provide('foo.bar.method');
goog.provide('foo.bar.CONSTANT');