Google的Javascript风格指南
9 附件
9.1 JSDoc标签参考
JSDoc在JavaScript中有多种用途。 除了用于生成文档外,它还用于控制工具。 最著名的是Closure Compiler类型注释。
9.1.1 类型注释和其他Closure Compiler注释
在Annotating JavaScript for the Closure Compiler 和Types in the Closure Type System中描述了Closure Compiler使用的JSDoc文档。
9.1.2 文档注释
除了用于Annotating JavaScript for the Closure Compiler 描述的JSDoc外,以下标记是通用的,并且由各种文档生成工具(例如JsDossier)很好地支持,以纯粹用于文档目的。
您可能还会在第三方代码中看到其他类型的JSDoc注释。 这些注释出现在JSDoc Toolkit Tag Reference中,但不被视为有效Google样式的一部分。
9.1.2.1 @author 或者 @owner - 不推荐
不推荐。
文法:@author username@google.com (First Last)
/**
* @fileoverview Utilities for handling textareas.
* @author kuth@google.com (Uthur Pendragon)
*/
记录文件的作者或测试的所有者,通常只在@fileoverview注释中使用。 单元测试仪表板使用@owner标记来确定谁拥有测试结果。
9.1.2.2 @bug
文法:@bug bugnumber
/** @bug 1234567 */
function testSomething() {
// …
}
/**
* @bug 1234568
* @bug 1234569
*/
function testTwoBugs() {
// …
}
指示给定测试功能回归测试会导致哪些错误。
多个错误应每个都有自己的@bug行,以使搜索回归测试尽可能容易。
9.1.2.3 @code -弃用, 不推荐使用
不推荐使用。 请改用Markdown反引号。
文法:{@code …}
由于历史原因,BatchItem
被写为{@code BatchItem}。
/** Processes pending `BatchItem` instances. */
function processBatchItems() {}
表示JSDoc描述中的术语是代码,因此可以在生成的文档中正确设置其格式。
9.1.2.4 @desc
文法:@desc Message description
/** @desc Notifying a user that their account has been created. */
exports.MSG_ACCOUNT_CREATED = goog.getMsg(
'Your account has been successfully created.');
9.1.2.5 @link
文法:{@link …}
此标记用于在生成的文档内生成交叉引用链接。
/** Processes pending {@link BatchItem} instances. */
function processBatchItems() {}
历史记录:@link标记也已用于在生成的文档中创建外部链接。 对于外部链接,请始终使用Markdown的链接语法:
/**
* This class implements a useful subset of the
* [native Event interface](https://dom.spec.whatwg.org/#event).
*/
class ApplicationEvent {}
9.1.2.6 @see
文法:@see Link
/**
* Adds a single item, recklessly.
* @see #addSafely
* @see goog.Collect
* @see goog.RecklessAdder#add
*/
将查询引用到另一个类函数或方法。
9.1.2.7 @supported
文法:@supported Description
/**
* @fileoverview Event Manager
* Provides an abstracted interface to the browsers' event systems.
* @supported IE10+, Chrome, Safari
*/
在文件概述中用于指示文件支持哪些浏览器。
9.1.3 适用于特定框架的注释
以下注释适用于特定框架。
9.1.3.1 @ngInject 特定于Angular 1
9.1.3.2 @polymerBehavior特定于Polymer
https://github.com/google/closure-compiler/wiki/Polymer-Pass
9.1.4 有关标准Closure Compiler批注的注释
以下标记曾经是标准标记,但现已弃用。
9.1.4.1 @expose - 已弃用,不要使用。
已弃用。使用@export和/或@nocollapse作为替代。
9.1.4.2 @inheritDoc - 已弃用,不要使用。
已弃用,使用@override作为替代。
9.2 经常被误解的样式规则
这是关于JavaScript的Google样式的一些鲜为人知或经常被误解的事实的集合。 (以下是正确的陈述;这不是神话列表。)
- 源文件中不需要版权声明或@author信用。 (也没有明确建议。)
- 对于如何对一个类的成员(5.4 类)进行排序,没有硬性规定。
- 空块通常可以用{}简洁地表示,如(4.1.3 空块:可能更精炼)中所述。
- 换行的主要指令是:更喜欢在较高的语法级别(4.5.1 在哪里中断)处断开。
- 字符串文字,注释和JSDoc中允许使用非ASCII字符,实际上,当它们使代码比等效的Unicode转义(2.3.3 非ASCII字符)更易于阅读时,建议使用非ASCII字符。
9.3 与样式相关的工具
存在以下工具来支持Google样式的各个方面。
9.3.1 Closure Compiler
该程序执行类型检查以及其他检查,优化和其他转换(例如ECMAScript 6到ECMAScript 5及以下版本的代码转换)。
9.3.2 clang-format
该程序将JavaScript源代码重新格式化为Google样式,并遵循了许多非必需但经常提高可读性的格式设置惯例。 由clang-format产生的输出符合样式指南。
不需要clang格式。 允许作者更改其输出,并允许审稿人要求此类更改; 争端以通常的方式解决。 但是,子树可以选择在本地选择加入此类实施。
9.3.3 Closure compiler linter
该程序检查各种失误和反模式。
9.3.4 一致性框架
JS Conformance Framework是Closure Compiler的一部分,该工具为开发人员提供了一种简单的方法,可以指定一组额外的检查,以使其在标准检查之上针对其代码库运行。 例如,一致性检查可能会禁止访问某些属性,禁止调用某个函数或缺少类型信息(未知)。
这些规则通常用于强制执行严格的限制(例如,定义全局变量,这可能会破坏代码库)和安全性模式(例如,使用eval或分配给innerHTML),或者更宽松地用于提高代码质量。
有关更多信息,请参见官方文档JS Conformance Framework。
9.4 旧版平台的例外
9.4.1 总览
本节介绍当代码作者无法使用现代ECMAScript 6语法时的例外情况和其他规则。 如果无法使用ECMAScript 6语法,则要求使用推荐样式的例外,并在此处概述:
- 允许使用var声明。
- 允许使用arguments。
- 允许没有默认值的可选参数。
9.4.2 使用var
9.4.2.1 var声明不是块作用域的
var声明的作用域是最接近的封闭函数,脚本或模块的开头,这可能会导致意外行为,尤其是对于在循环内部引用var声明的函数闭包而言。 以下代码给出了一个示例:
for (var i = 0; i < 3; ++i) {
var iteration = i;
setTimeout(function() { console.log(iteration); }, i*1000);
}
// logs 2, 2, 2 -- NOT 0, 1, 2
// because `iteration` is function-scoped, not local to the loop.
9.4.2.2 声明尽可能接近首次使用的变量
即使var声明的范围仅限于封闭函数的开头,但出于可读性的目的,var声明应尽可能接近其首次使用。 但是,如果在块外引用了该变量,则不要在块内放置var声明。 例如:
function sillyFunction() {
var count = 0;
for (var x in y) {
// "count" could be declared here, but don't do that.
count++;
}
console.log(count + ' items in y');
}
9.4.2.3 将@const用于常量变量
对于将使用const关键字的全局声明(如果可用),请使用@const注释var声明(这对于局部变量是可选的)。
9.4.3 不要使用块作用域函数声明
不要这样做:
if (x) {
function foo() {}
}
尽管在ECMAScript 6之前实现的大多数JavaScript VM都在块内支持函数声明,但它尚未标准化。 实现彼此之间以及与现在标准的ECMAScript 6行为(用于块范围函数声明)不一致。 ECMAScript 5和更高版本仅允许在脚本或函数的根语句列表中进行函数声明,并在严格模式下将其明确禁止在块作用域中使用。
为了获得一致的行为,请使用通过函数表达式初始化的var在块内定义函数:
if (x) {
var foo = function() {};
}
9.4.4 使用goog.provide / goog.require进行依赖管理
9.4.4.1 总结
警告:不建议使用goog.provide依赖项管理。 所有新文件,即使在使用goog.provide的旧文件项目中,也应使用goog.module。 以下规则仅适用于预先存在的goog.provide文件。
- 将所有goog.provides放在第一位,goog.requires放在第二位。 空行将提供与需求分开。
- 按字母顺序对条目进行排序(大写优先)。
- 不要包装goog.provide和goog.require语句。 必要时超过80列。
- 仅提供顶级符号。
goog.provide语句应组合在一起并放在最前面。 所有goog.require语句都应遵循。 这两个列表应以空行分隔。
与其他语言的import语句相似,即使goog.provide和goog.require语句超过了80列的行长限制,也应将它们写在一行中。
这些行应按字母顺序排序,大写字母排在最前面:
goog.provide('namespace.MyClass');
goog.provide('namespace.helperFoo');
goog.require('an.extremelyLongNamespace.thatSomeoneThought.wouldBeNice.andNowItIsLonger.Than80Columns');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classes');
goog.require('goog.dominoes');
在类上定义的所有成员都应在同一文件中。 包含多个在同一类上定义的成员的文件中应仅提供顶级类(例如,枚举,内部类等)。
这样做:
goog.provide('namespace.MyClass');
不要这样做:
goog.provide('namespace.MyClass');
goog.provide('namespace.MyClass.CONSTANT');
goog.provide('namespace.MyClass.Enum');
goog.provide('namespace.MyClass.InnerClass');
goog.provide('namespace.MyClass.TypeDef');
goog.provide('namespace.MyClass.staticMethod');
还可以提供名称空间上的成员:
goog.provide('foo.bar');
goog.provide('foo.bar.CONSTANT');
goog.provide('foo.bar.method');
9.4.4.2 使用Goog.scope起别名
警告:不建议使用goog.scope。 即使在使用现有goog.scope的项目中,新文件也不应使用goog.scope。
goog.scope可以用于使用goog.provide / goog.require依赖项管理来缩短对代码中命名空间符号的引用。
每个文件只能添加一个goog.scope调用。 始终将其放在全局范围内。
开头的goog.scope(function(){调用前必须紧跟一个空白行,并跟随所有goog.provide语句,goog.require语句或顶级注释。该调用必须在文件的最后一行关闭 。//将goog.scope追加到合并范围的结束声明中,将分号和注释之间的空格分开两个空格。
与C ++名称空间类似,请勿在goog.scope声明下缩进。 而是从0列继续。
仅为不会重新分配给另一个对象的名称(例如,大多数构造函数,枚举和名称空间)创建别名。 不要这样做(有关如何为构造函数添加别名,请参见下文):
goog.scope(function() {
var Button = goog.ui.Button;
Button = function() { ... };
...
名称必须与它们别名的全局名称的最后一个属性相同。
goog.provide('my.module.SomeType');
goog.require('goog.dom');
goog.require('goog.ui.Button');
goog.scope(function() {
var Button = goog.ui.Button;
var dom = goog.dom;
// Alias new types after the constructor declaration.
my.module.SomeType = function() { ... };
var SomeType = my.module.SomeType;
// Declare methods on the prototype as usual:
SomeType.prototype.findButton = function() {
// Button as aliased above.
this.button = new Button(dom.getElement('my-button'));
};
...
}); // goog.scope
9.4.4.3 goog.forwardDeclare
最好使用goog.requireType代替goog.forwardDeclare来打破同一库中文件之间的循环依赖关系。 与goog.require不同,goog.requireType语句允许在定义名称空间之前导入它。
goog.forwardDeclare仍可在旧版代码中使用,以打破跨越库边界的循环引用,但是应构造新的代码以避免这种情况。
goog.forwardDeclare语句必须遵循与goog.require和goog.requireType相同的样式规则。 goog.forwardDeclare,goog.require和goog.requireType语句的整个块均按字母顺序排序。