Google JavaScript样式指南
Google JavaScript样式指南
目录
1简介![](https://google.github.io/styleguide/include/link.png)
本文档用作JavaScript编程语言中Google源代码编码标准的完整定义。JavaScript源文件被描述为Google风格,当且仅当它符合此处的规则时。
与其他编程风格指南一样,所涉及的问题不仅包括格式化的美学问题,还包括其他类型的约定或编码标准。但是,本文档主要关注我们普遍遵循的严格规则,并避免提供不明确可执行的建议(无论是通过人工还是工具)。
1.1术语说明![](https://google.github.io/styleguide/include/link.png)
在本文件中,除非另有说明:
-
术语注释总是指实现注释。我们不使用
文档注释
这一短语,而是使用常用术语“JSDoc”来表示人类可读的文本和机器可读的注释/** … */
。 -
使用短语时,本样式指南使用RFC 2119术语必须, 不得,应该,不应该,也可以。术语偏好和 避免分别对应应该和不应该对应。命令性和陈述性陈述是规定性的,并且必须符合。
其他术语说明
将在整个文件中偶尔出现。
1.2指南说明![](https://google.github.io/styleguide/include/link.png)
本文档中的示例代码是非规范性的。也就是说,虽然示例是Google风格,但它们可能并没有说明代表代码的唯一时尚方式。在示例中进行的可选格式选择不得作为规则强制执行。
2源文件基础知识![](https://google.github.io/styleguide/include/link.png)
2.1文件名![](https://google.github.io/styleguide/include/link.png)
文件名必须全部小写,并且可以包含下划线(_
)或短划线(-
),但不包含其他标点符号。遵循项目使用的约定。文件名的扩展名必须是.js
。
2.2文件编码:UTF-8![](https://google.github.io/styleguide/include/link.png)
源文件以UTF-8编码。
2.3特殊字符![](https://google.github.io/styleguide/include/link.png)
2.3.1空白字符![](https://google.github.io/styleguide/include/link.png)
除了行终止符序列之外,ASCII水平空格字符(0x20)是唯一出现在源文件中任何位置的空白字符。这意味着
-
字符串文字中的所有其他空白字符都被转义,并且
-
制表符不用于缩进。
2.3.2特殊转义序列![](https://google.github.io/styleguide/include/link.png)
对于具有特殊的转义序列(任何字符\'
,\"
,\\
,\b
, \f
,\n
,\r
,\t
,\v
),该序列使用,而不是对应的数字逃逸(例如\x0a
,\u000a
或\u{a}
)。传统的八进制转义从未使用过。
2.3.3非ASCII字符![](https://google.github.io/styleguide/include/link.png)
对于剩余的非ASCII字符,使用实际的Unicode字符(例如∞
)或等效的十六进制或Unicode转义(例如\u221e
),这取决于哪些使代码更易于阅读和理解。
提示:在Unicode转义情况下,有时即使使用实际的Unicode字符,解释性注释也会非常有用。
例 | 讨论 |
---|---|
const units = 'μs'; |
最佳:即使没有评论也完全清楚。 |
const units = '\u03bcs'; // 'μs' |
允许,但没有理由这样做。 |
const units = '\u03bcs'; // Greek letter mu, 's' |
允许,但尴尬,容易出错。 |
const units = '\u03bcs'; |
差:读者不知道这是什么。 |
return '\ufeff' + content; // byte order mark |
好:对不可打印的字符使用转义,并在必要时进行注释。 |
提示:由于担心某些程序可能无法正确处理非ASCII字符,因此不要让代码的可读性降低。如果发生这种情况,那些程序就会被破坏,必须修复它们。
3源文件结构![](https://google.github.io/styleguide/include/link.png)
源文件按顺序包含:
- 许可证或版权信息(如果有)
@fileoverview
JSDoc,如果存在的话goog.module
声明goog.require
声明- 该文件的实现
除了文件的实现之外,正好有一个空行用于分隔存在的每个部分,其前面可能有1或2个空行。
3.1许可或版权信息(如果有)![](https://google.github.io/styleguide/include/link.png)
如果许可或版权信息属于文件,则属于此处。
3.2 @fileoverview
JSDoc,如果存在的话![](https://google.github.io/styleguide/include/link.png)
有关格式规则,请参见7.5顶级/文件级注释。
3.3 goog.module
声明![](https://google.github.io/styleguide/include/link.png)
所有文件必须goog.module
在一行中只声明一个名称:包含goog.module
声明的行不得包装,因此是80列限制的例外。
goog.module的整个参数是定义命名空间的。它是包名称(反映代码所在目录结构片段的标识符),以及它定义连接到结尾的主类/枚举/接口。
例
goog.module( 'search.urlHistory.UrlHistoryService');
3.3.1层次结构![](https://google.github.io/styleguide/include/link.png)
模块命名空间可能永远不会被命名为另一个模块命名空间的直接子节点。
非法:
goog.module( 'foo.bar'); //'foo.bar.qux'会好的 goog.module( 'foo.bar.baz');
目录层次结构反映了命名空间层次结构,因此深层嵌套子节点是更高级别父目录的子目录。请注意,这意味着“父”命名空间组的所有者必须知道所有子命名空间,因为它们存在于同一目录中。
3.3.2 goog.setTestOnly
![](https://google.github.io/styleguide/include/link.png)
单个goog.module
语句可以选择性地跟随对goog.setTestOnly()的调用。
3.3.3 goog.module.declareLegacyNamespace
![](https://google.github.io/styleguide/include/link.png)
单个goog.module
语句可以选择性地跟随调用 goog.module.declareLegacyNamespace();
。goog.module.declareLegacyNamespace()
尽可能避免 。
例:
goog.module( 'my.test.helpers'); goog.module.declareLegacyNamespace(); goog.setTestOnly();
goog.module.declareLegacyNamespace
存在是为了简化从传统的基于对象层次结构的命名空间的转换,但带有一些命名限制。由于必须在父命名空间之后创建子模块名称,因此该名称不能是任何其他名称的子项或父项 goog.module
(例如,goog.module('parent');
并且 goog.module('parent.child');
不能同时安全存在,也不能 goog.module('parent');
和goog.module('parent.child.grandchild');
)。
3.3.4 ES6模块![](https://google.github.io/styleguide/include/link.png)
不要使用ES6模块(即export
和import
关键字),因为它们的语义尚未最终确定。请注意,一旦语义完全标准化,将重新审视此策略。
3.4 goog.require
陈述![](https://google.github.io/styleguide/include/link.png)
使用goog.require
语句完成导入,在模块声明后立即组合在一起。每个都goog.require
被分配给一个常量别名,或者被解构为几个常量别名。这些别名是引用require
d依赖关系的唯一可接受的方式,无论是在代码中还是在类型注释中:除非作为参数,否则永远不会使用完全限定名goog.require
。别名应尽可能与导入模块名称的最终点分隔组件匹配,但可能包含其他组件(如果需要消除歧义,或者如果显着改进,则使用适当的套管使别名'套管仍能正确识别其类型)可读性。goog.require
语句可能不会出现在文件中的任何其他位置。
如果仅为其副作用导入模块,则可以省略分配,但完全限定的名称可能不会出现在文件中的任何其他位置。需要注释来解释为什么需要这样做并抑制编译器警告。
这些行按照以下规则排序:所有要求在左侧的名称首先出现,按字母顺序按这些名称排序。然后解构需要,再次按左侧的名称排序。最后,任何goog.require
独立的调用(通常这些是针对其副作用导入的模块)。
提示:无需记住此订单并手动强制执行。您可以依靠IDE来报告未正确排序的需求。
如果长别名或模块名称会导致行超过80列限制,则不得包装:goog.require行是80列限制的例外。
例:
const MyClass = goog.require('some.package.MyClass'); const NsMyClass = goog.require('other.ns.MyClass'); const googAsserts = goog.require('goog.asserts'); const testingAsserts = goog.require('goog.testing.asserts'); const than80columns = goog.require('pretend.this.is.longer.than80columns'); const {clear,forEach,map} = goog.require('goog.array'); / ** @suppress {extraRequire}初始化MyFramework。* / goog.require( 'my.framework.initialization');
非法:
const randomName = goog.require('something.else'); //名称必须匹配 const {clear,forEach,map} = //不要破坏行 goog.require( 'goog.array'); function someFunction(){ const alias = goog.require('my.long.name.alias'); //必须在顶级 // ... }
3.4.1 goog.forwardDeclare
![](https://google.github.io/styleguide/include/link.png)
goog.forwardDeclare
不经常需要,但它是打破循环依赖或引用后期加载代码的有用工具。这些陈述组合在一起,并紧跟任何goog.require
陈述。一个 goog.forwardDeclare
语句必须遵循相同的样式规则的 goog.require
声明。
3.5文件的实现![](https://google.github.io/styleguide/include/link.png)
在声明所有依赖性信息之后(由至少一个空行分隔)之后的实际实现。
这可能包括任何模块本地声明(常量,变量,类,函数等),以及任何导出的符号。
4格式化![](https://google.github.io/styleguide/include/link.png)
术语注意:类似块的构造是指类,函数,方法或大括号分隔的代码块的主体。请注意,通过 5.2数组文字和5.3对象文字,可以选择将任何数组或对象文字视为类似于块的结构。
提示:使用clang-format
。JavaScript社区已投入精力确保clang格式在JavaScript文件上做正确的事情
。clang-format
与几位受欢迎的编辑集成。
4.1大括号![](https://google.github.io/styleguide/include/link.png)
4.1.1支架用于所有控制结构![](https://google.github.io/styleguide/include/link.png)
大括号都需要所有的控制结构(即if
,else
,for
,do
, while
,以及任何其他),即使身体只包含一个声明。非空块的第一个语句必须从它自己的行开始。
非法:
if(someVeryLongCondition()) 做一点事(); for(let i = 0; i <foo.length; i ++)bar(foo [i]);
例外:一个简单的if语句可以完全放在一行而没有包装(并且没有else)可以保留在一行中,当它提高可读性时没有括号。这是控制结构可以省略大括号和换行符的唯一情况。
if(shortCondition())返回;
4.1.2非空块:K&R风格![](https://google.github.io/styleguide/include/link.png)
大括号遵循Kernighan和Ritchie风格(埃及括号
),用于 非空块和块状结构:
- 开口支架前没有断线。
- 开口支撑后换行。
- 关闭括号前的换行符。
- 如果该大括号终止语句或函数或类语句的主体或类方法,则在大括号后的换行符。具体而言,有没有支架后换行符如果随后
else
,catch
,while
,或逗号,分号,或右括号。
例:
class InnerClass { 构造函数(){} / ** @param {number} foo * / method(foo){ if(condition(foo)){ 尝试{ //注意:这可能会失败。 东西(); } catch(err){ 恢复(); } } } }
4.1.3空块:可能简洁![](https://google.github.io/styleguide/include/link.png)
空块或块状结构可以在打开后立即关闭,其间没有字符,空格或换行符(即{}
), 除非它是多块语句的一部分(直接包含多个块的语句):if
/ else
或try
/ catch
/ finally
)。
例:
function doNothing(){}
非法:
if(condition){ // ... } else if(otherCondition){} else { // ... } 尝试{ // ... } catch(e){}
4.2块缩进:+2个空格![](https://google.github.io/styleguide/include/link.png)
每次打开新的块或块状构造时,缩进都会增加两个空格。当块结束时,缩进返回到先前的缩进级别。缩进级别适用于整个块中的代码和注释。(参见4.1.2非空块中的示例:K&R样式)。
4.2.1数组文字:可选择块状
![](https://google.github.io/styleguide/include/link.png)
任何数组文字都可以选择格式化,就好像它是一个“块状结构”。例如,以下都是有效的(不是详尽的列表):
const a = [ 0, 1, 2, ]。 const b = [0,1,2];
const c = [0,1,2]; someMethod(foo,[ 0,1,2, ],酒吧);
允许其他组合,特别是在强调元素之间的语义分组时,但不应仅用于减少较大数组的垂直大小。
4.2.2对象文字:可选择块状
![](https://google.github.io/styleguide/include/link.png)
任何对象文字都可以选择格式化,就好像它是一个“块状结构”。相同的例子适用于4.2.1数组文字:可选的块状。例如,以下都是有效的(不是详尽的列表):
const a = { a:0, b:1, }; const b = {a:0,b:1};
const c = {a:0,b:1}; someMethod(foo,{ a:0,b:1, },酒吧);
4.2.3类文字![](https://google.github.io/styleguide/include/link.png)
类文字(无论是声明还是表达式)缩进为块。不要在方法之后添加分号,或者在类声明的右括号之后添加分号 (包含类表达式的赋值 - 如赋值 - 仍以分号结尾)。除非类扩展了模板化类型,否则请使用extends
关键字,而不是 @extends
JSDoc注释。
例:
class Foo { constructor(){ / ** @type {number} * / this.x = 42; } / ** @return {number} * / 方法() { 返回this.x; } } Foo.Empty = class {};
/ ** @extends {Foo <string>} * / foo.Bar = class extends Foo { / ** @override * / 方法() { return super.method()/ 2; } }; / ** @interface * / class Frobnicator { / ** @param {string}消息* / frobnicate(消息){} }
4.2.4函数表达式![](https://google.github.io/styleguide/include/link.png)
在函数调用的参数列表中声明匿名函数时,函数体将比前一个缩进深度缩进两个空格。
例:
prefix.something.reallyLongFunctionName('whatever',(a1,a2)=> { //相对于缩进深度缩进函数体+2 //上面一行的'prefix'语句。 if(a1.equals(a2)){ someOtherLongFunctionName(A1); } else { andNowForSomethingCompletelyDifferent(a2.parrot); } }); some.reallyLongFunctionCall(arg1,arg2,arg3) .thatsWrapped() .then((result)=> { //相对于缩进深度缩进函数体+2 //'.then()'调用。 if(result){ result.use(); } });
4.2.5切换语句![](https://google.github.io/styleguide/include/link.png)
与任何其他块一样,开关块的内容缩进为+2。
在切换标签之后,出现换行符,并且缩进级别增加+2,就像打开一个块一样。如果词法作用域需要,可以使用显式块。以下开关标签返回到先前的缩进级别,就像块已关闭一样。
a break
和以下情况之间的空行是可选的。
例:
开关(动物){ case Animal.BANDERSNATCH: handleBandersnatch(); 打破; case Animal.JABBERWOCK: handleJabberwock(); 打破; 默认: 抛出新错误('未知动物'); }
4.3声明![](https://google.github.io/styleguide/include/link.png)
4.3.1每行一个语句![](https://google.github.io/styleguide/include/link.png)
每个语句后面都有一个换行符。
4.3.2分号是必需的![](https://google.github.io/styleguide/include/link.png)
每个语句必须以分号结束。禁止依赖自动分号插入。
4.4柱限:80![](https://google.github.io/styleguide/include/link.png)
JavaScript代码的列限制为80个字符。除非另有说明,否则任何超出此限制的行都必须换行,如 4.5换行中所述。
例外:
- 不能遵守列限制的行(例如,JSDoc中的长URL或要复制和粘贴的shell命令)。
goog.module
和goog.require
语句(参见3.3 goog.module语句和 3.4 goog.require语句)。
4.5换行![](https://google.github.io/styleguide/include/link.png)
术语注意:换行定义为将单个表达式分成多行。
有没有表现出全面的,确定性的公式究竟如何线路缠绕在每一种情况。通常有几种有效的方法来包装同一段代码。
注意:虽然换行的典型原因是为了避免溢出列限制,但即使是实际符合列限制的代码也可能由作者自行决定是否换行。
提示:提取方法或局部变量可以解决问题,而无需换行。
4.5.1在哪里打破![](https://google.github.io/styleguide/include/link.png)
换行的主要指令是:更喜欢在更高的句法层面打破。
首选:
currentEstimate = calc(currentEstimate + x * currentEstimate)/ 2.0F;
灰心:
currentEstimate = calc(currentEstimate + x * currentEstimate)/ 2.0f;
在前面的例子中,从最高到最低的句法级别如下:赋值,除法,函数调用,参数,数字常量。
运算符包含如下:
- 当一条线在操作员处断开时,断点出现在符号之后。(请注意,这与Google风格的Java风格不同。)
- 这不适用于
dot
(.
),它实际上不是运算符。
- 这不适用于
- 方法或构造函数名称保持附加到其后面的左括号(
(
)。 - 逗号(
,
)保持附加到其前面的标记。
注意:换行的主要目标是拥有清晰的代码,而不一定是适合最小行数的代码。
4.5.2缩进连续行至少+4个空格![](https://google.github.io/styleguide/include/link.png)
当换行时,第一行(每个延续行)之后的每一行从原始行缩进至少+4,除非它属于块缩进的规则。
当存在多个连续线时,压痕可以适当地变化超过+4。通常,更深层次的句法级别的连续行用4的较大倍数缩进,当且仅当它们以语法并行元素开头时,两行使用相同的缩进级别。
4.6.3水平对齐:不鼓励使用可变数量的空格来阻止某些令牌与前一行对齐。
4.6空白![](https://google.github.io/styleguide/include/link.png)
4.6.1垂直空白![](https://google.github.io/styleguide/include/link.png)
出现一个空白行:
- 在类或对象文字中的连续方法之间
- 例外:对象文字中两个连续属性定义之间的空行(它们之间没有其他代码)是可选的。根据需要使用这样的空行来创建字段的逻辑分组。
- 在方法体内,谨慎地创建语句的逻辑分组。不允许在函数体的开头或结尾处出现空行。
- 可选地在类或对象文字中的第一个或最后一个方法之前(既不鼓励也不鼓励)。
- 按照本文档其他部分的要求(例如 3.4 goog.require语句)。
允许多个连续的空白行,但从不需要(也不鼓励)。
4.6.2水平空格![](https://google.github.io/styleguide/include/link.png)
水平空白的使用取决于位置,并分为三大类:前导(在行的开头),尾随(在行的末尾)和内部。领先的空白(即缩进)在别处得到解决。禁止使用尾随空格。
除了语言或其他样式规则所要求的内容之外,除了文字,注释和JSDoc之外,单个内部ASCII空间也仅出现在以下位置。
- 分离任何保留字(如
if
,for
或catch
)从一个开括号((
它后面在该行)。 - 将任何保留字(例如
else
或catch
)与}
该行前面的右大括号()分开。 - 在任何打开大括号(
{
)之前,有两个例外:- 在作为函数的第一个参数或数组文字中的第一个元素的对象文字之前(例如
foo({a: [{c: d}]})
)。 - 在模板扩展中,因为它被语言禁止(例如
abc${1 + 2}def
)。
- 在作为函数的第一个参数或数组文字中的第一个元素的对象文字之前(例如
- 在任何二元或三元运算符的两边。
- 在逗号(
,
)或分号(;
)之后。请注意,在这些字符之前绝不允许使用空格。 - 在
:
对象文字中冒号()之后。 - 在双斜杠(
//
)的两侧开始一行结束注释。这里允许多个空格,但不是必需的。 - 在打开JSDoc注释字符后和关闭字符的两边(例如,对于短格式类型声明或强制转换:
this.foo = /** @type {number} */ (bar);
或function(/** string */ foo) {
)。
4.6.3水平对齐:不鼓励![](https://google.github.io/styleguide/include/link.png)
术语注意:水平对齐是在代码中添加可变数量的附加空格的做法,目的是使某些标记直接出现在前一行的某些其他标记下方。
这种做法是允许的,但谷歌风格通常不鼓励这种做法。甚至不需要在已经使用过的地方保持水平对齐。
这是一个没有对齐的示例,后面跟一个对齐。两者都是允许的,但后者是不鼓励的:
{ 微小的:42,//这很棒 更长:435,//这也是 }; { 微小:42,//允许,但未来的编辑 更长:435,//可能会使它不对齐 };
提示:对齐可以提高可读性,但会为将来的维护带来问题。考虑一下需要触及一条线的未来变化。这种改变可能会使以前令人愉悦的格式化变得严重,并且这是允许的。更常见的是,它会提示编码人员(也许你)调整附近行的空白,这可能会引发一连串的重新格式化。那个单线变化现在有一个爆炸半径。
这可能会导致无意义的忙碌工作,但最多它仍然会破坏版本历史信息,减慢审阅者的速度并加剧合并冲突。
4.6.4函数参数![](https://google.github.io/styleguide/include/link.png)
希望将所有函数参数放在与函数名称相同的行上。如果这样做会超过80列限制,则参数必须以可读的方式换行。为了节省空间,您可以尽可能接近80,或者将每个参数放在自己的行上以增强可读性。缩进应该是四个空格。允许对齐括号,但不鼓励。以下是参数包装最常见的模式:
//参数从一个新行开始,缩进四个空格。首选的时候 //参数与函数名称(或关键字)不在同一行 //“功能”)但完全适合第二行。工作时间很长 //函数名称,无需重新定义即可重命名,空间不足。 做一点事( descriptiveArgumentOne,descriptiveArgumentTwo,descriptiveArgumentThree){ // ... } //如果参数列表较长,请换行80.使用较少的垂直空间, //但违反了矩形规则,因此不推荐使用。 doSomething(veryDescriptiveArgumentNumberOne,veryDescriptiveArgumentTwo, tableModelEventHandlerProxy,artichokeDescriptorAdapterIterator){ // ... } //四个空格,每行一个参数。使用长函数名称, //幸存重命名,并强调每个参数。 做一点事( veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator){ // ... }
4.7分组括号:推荐![](https://google.github.io/styleguide/include/link.png)
只有当作者和审阅者同意没有合理的机会在没有它们的情况下错误解释代码时,才会省略可选的分组括号,也不会使代码更易于阅读。它是不是 合理的假设,每个读者有记忆的整个运算符优先级表。
以下不要使用不必要的括号整个表达式 delete
,typeof
,void
,return
,throw
,case
,in
,of
,或yield
。
类型转换需要括号:/** @type {!Foo} */ (foo)
。
4.8评论![](https://google.github.io/styleguide/include/link.png)
本节介绍实现注释。JSDoc在7 JSDoc中单独解决。
4.8.1阻止评论风格![](https://google.github.io/styleguide/include/link.png)
块注释与周围代码的缩进级别相同。他们可能是/* … */
或者是//
风格。对于多行/* … */
注释,后续行必须以*与*
前一行的对齐开头,以使注释显而易见,没有额外的上下文。只要值和方法名称没有充分表达含义,“参数名称”注释就应出现在值之后。
/ * * 这是 * 好的。 * / // 所以 // 这是。 / *这也很好。* / someFunction(obviousParam,true / * shouldRender * /,'hello'/ * name * /);
注释不包含在用星号或其他字符绘制的框中。
不要将JSDoc(/** … */
)用于上述任何实现注释。
5语言功能![](https://google.github.io/styleguide/include/link.png)
JavaScript包含许多可疑(甚至危险)的功能。本节描述了可能使用或未使用的功能,以及对其使用的任何其他限制。
5.1局部变量声明![](https://google.github.io/styleguide/include/link.png)
5.1.1使用const
和let
![](https://google.github.io/styleguide/include/link.png)
声明所有的局部变量有两种const
或let
。除非需要重新分配变量,否则默认使用const。将var
不得使用关键字。
5.1.2每个声明一个变量![](https://google.github.io/styleguide/include/link.png)
每个局部变量声明只声明一个变量:声明,例如let a = 1, b = 2;
未使用。
5.1.3在需要时声明,尽快初始化![](https://google.github.io/styleguide/include/link.png)
局部变量不能习惯性地在其包含块或块状结构的开始申报。相反,局部变量被声明为接近它们首次使用的点(在合理范围内),以最小化它们的范围。
5.1.4根据需要声明类型![](https://google.github.io/styleguide/include/link.png)
可以在声明上方的行上添加JSDoc类型注释,或者在变量名称之前添加内联。
例:
const / **!Array <number> * / data = []; / ** @type {!Array <number>} * / const data = [];
提示:在许多情况下,编译器可以推断模板化类型而不是其参数。当初始化文字或构造函数调用不包含模板参数类型的任何值(例如,空数组,对象,Map
s或Set
s),或者在闭包中修改变量时,尤其如此。在这些情况下,局部变量类型注释特别有用,否则编译器会将模板参数推断为未知。
5.2数组文字![](https://google.github.io/styleguide/include/link.png)
5.2.1使用尾随逗号![](https://google.github.io/styleguide/include/link.png)
每当最终元素和结束括号之间存在换行符时,请包含尾随逗号。
例:
const值= [ '第一价值', '第二价值', ]。
5.2.2不要使用可变参数Array
构造函数![](https://google.github.io/styleguide/include/link.png)
如果添加或删除参数,则构造函数容易出错。请改用文字。
非法:
const a1 = new Array(x1,x2,x3); const a2 = new Array(x1,x2); const a3 = new Array(x1); const a4 = new Array();
除了第三种情况之外,这可以正常工作:if x1
是一个整数然后 a3
是x1
所有元素都是大小的数组undefined
。如果x1
是任何其他数字,那么将抛出异常,如果它是其他任何东西,那么它将是单元素数组。
相反,写
const a1 = [x1,x2,x3]; const a2 = [x1,x2]; const a3 = [x1]; const a4 = [];
new Array(length)
适当时允许使用显式分配给定长度的数组。
5.2.3非数字属性![](https://google.github.io/styleguide/include/link.png)
不要在数组上定义或使用非数字属性(除了 length
)。使用Map
(或Object
)代替。
5.2.4解构![](https://google.github.io/styleguide/include/link.png)
可以在赋值的左侧使用数组文字来执行解构(例如,从单个数组或可迭代解包多个值时)。可以包括最终的rest
元素(...
在变量名和变量名之间没有空格 )。如果未使用元素,则应省略元素。
const [a,b,c,... rest] = generateResults(); 让[,b ,, d] = someArray;
解构也可以用于函数参数(请注意,参数名称是必需的但是被忽略)。[]
如果结构化数组参数是可选的,则始终指定为默认值,并在左侧提供默认值:
/ ** @param {!Array <number> =} param1 * / function optionalDestructuring([a = 4,b = 2] = []){...};
非法:
function badDestructuring([a,b] = [4,2]){...};
提示:对于(un)将多个值打包到函数的参数或返回中,尽可能将对象解构更改为数组解构,因为它允许命名单个元素并为每个元素指定不同的类型。*
5.2.5传播运营商![](https://google.github.io/styleguide/include/link.png)
数组文字可以包括扩展运算符(...
)以展平一个或多个其他迭代中的元素。应该使用扩展运算符而不是更笨拙的构造Array.prototype
。之后没有空间 ...
。
例:
[... foo] //首选Array.prototype.slice.call(foo) [... foo,... bar] //首选foo.concat(bar)
5.3对象文字![](https://google.github.io/styleguide/include/link.png)
5.3.1使用尾随逗号![](https://google.github.io/styleguide/include/link.png)
每当最终属性和右大括号之间存在换行符时,请包含尾随逗号。
5.3.2不要使用Object
构造函数![](https://google.github.io/styleguide/include/link.png)
虽然Object
没有同样的问题Array
,但仍然不允许一致性。请改用对象文字({}
或{a: 0, b: 1, c: 2}
)。
5.3.3不要混合引用和不引用的密钥![](https://google.github.io/styleguide/include/link.png)
对象文字可以表示结构(带有不带引号的键和/或符号)或dicts(带引号和/或计算键)。不要在单个对象文字中混合使用这些键类型。
非法:
{ a:42,// struct-style unquoted key 'b':43,// dict-style引用键 }
5.3.4计算属性名称![](https://google.github.io/styleguide/include/link.png)
{['key' + foo()]: 42}
允许使用计算属性名称(例如),并且将其视为dict样式(引用)键(即,不得与非引用键混合),除非计算属性是符号(例如,[Symbol.iterator]
)。枚举值也可用于计算键,但不应与同一文字中的非枚举键混合使用。
5.3.5方法速记![](https://google.github.io/styleguide/include/link.png)
可以使用方法shorthand({method() {… }}
)代替冒号后面紧跟一个function
或箭头函数文字,在对象文字上定义方法。
例:
返回{ 东西:'糖果', 方法() { 归还这个。//返回'candy' }, };
请注意,this
在方法简写中或function
引用对象文字本身,而this
在箭头函数中引用对象文字之外的范围。
例:
class { getObjectLiteral(){ this.stuff ='fruit'; 返回{ 东西:'糖果', 方法:()=> this.stuff,//返回'fruit' }; } }
5.3.6速记属性![](https://google.github.io/styleguide/include/link.png)
对象文字允许使用速记属性。
例:
const foo = 1; const bar = 2; const obj = { FOO, 酒吧, method(){return this.foo + this.bar; }, }; assertEquals(3,obj.method());
5.3.7解构![](https://google.github.io/styleguide/include/link.png)
可以在赋值的左侧使用对象解构模式来执行解构并从单个对象解包多个值。
结构化对象也可以用作函数参数,但应尽可能简单:单个级别的不带引号的速记属性。嵌套和计算属性的更深层次可能不会用于参数解构。在destructured参数的左侧指定任何默认值({str = 'some default'} = {}
而不是{str} = {str: 'some default'}
),如果解构对象本身是可选的,则必须默认为{}
。可以为destructured参数提供JSDoc任何名称(名称未使用但编译器需要)。
例:
/ ** * @param {string}普通 * @param {{num:(number | undefined),str:(string | undefined)} =} param1 * num:做某事的次数。 * str:用来做东西的字符串。 * / 函数destructured(普通,{num,str ='some default'} = {})
非法:
/ ** @param {{x:{num:(number | undefined),str:(string | undefined)}}} param1 * / function nestedTooDeeply({x:{num,str}}){}; / ** @param {{num:(number | undefined),str:(string | undefined)} =} param1 * / function nonShorthandProperty({num:a,str:b} = {}){}; / ** @param {{a:number,b:number}} param1 * / function computedKey({a,b,[a + b]:c}){}; / ** @param {{a:number,b:string} =} param1 * / function nontrivialDefault({a,b} = {a:2,b:4}){};
解构也可以用于goog.require
语句,在这种情况下不能包装:整个语句占用一行,无论它有多长(参见3.4 goog.require语句)。
5.3.8枚举![](https://google.github.io/styleguide/include/link.png)
通过将@enum
注释添加到对象文字来定义枚举。定义后,可能无法将其他属性添加到枚举中。枚举必须是常量,所有枚举值必须是不可变的。
/ ** *支持的温标。 * @enum {string} * / const TemperatureScale = { CELSIUS:'摄氏', FAHRENHEIT:'华氏', }; / ** *枚举有两个选项。 * @enum {number} * / const Option = { / **使用的选项应该是第一个。* / FIRST_OPTION:1, / **两个选项中的第二个。* / SECOND_OPTION:2, };
5.4课程![](https://google.github.io/styleguide/include/link.png)
5.4.1构造函数![](https://google.github.io/styleguide/include/link.png)
具体类的构造函数是可选的。子类构造函数必须super()
在设置任何字段或以其他方式访问之前调用 this
。接口不能定义构造函数。
5.4.2字段![](https://google.github.io/styleguide/include/link.png)
在构造函数中设置所有具体对象的字段(即除方法之外的所有属性)。注释永远不会重新分配的字段@const
(这些字段不必非常不可变)。必须使用私有字段进行注释, @private
并且其名称必须以尾随下划线结尾。字段永远不会设置在具体类上prototype
。
例:
class Foo { constructor(){ / ** @private @const {!Bar} * / this.bar_ = computeBar(); } }
提示:在构造函数完成后,绝不应将属性添加到实例或从实例中删除属性,因为它会显着阻碍VM的优化能力。如有必要,稍后初始化的字段应undefined
在构造函数中显式设置为以防止以后的形状更改。添加 @struct
到对象将检查未添加/访问未声明的属性。默认情况下,类会添加此类。
5.4.3计算属性![](https://google.github.io/styleguide/include/link.png)
当属性是符号时,计算属性只能在类中使用。不允许使用Dict样式属性(即,引用或计算的非符号键,如5.3.3中所定义,不混合引用和不带引号的键)。[Symbol.iterator]
应该为逻辑上可迭代的任何类定义一个 方法。除此之外,Symbol
应谨慎使用。
提示:请小心使用任何其他内置符号(例如Symbol.isConcatSpreadable
),因为它们不是由编译器填充的,因此不适用于旧版浏览器。
5.4.4静态方法![](https://google.github.io/styleguide/include/link.png)
在不干扰可读性的地方,更喜欢模块本地函数而不是私有静态方法。
静态方法只应在基类本身上调用。不应该在包含动态实例的变量上调用静态方法,动态实例可以是构造函数或子类构造函数(@nocollapse
如果已完成,则必须定义 ),并且不能直接在未定义方法的子类上调用本身。
非法:
class Base {/ ** @nocollapse * / static foo(){}} class Sub扩展Base {} function callFoo(cls){cls.foo(); } //劝阻:不要动态调用静态方法 Sub.foo(); //非法:不要在没有自己定义它的子类上调用静态方法
5.4.5旧式类声明![](https://google.github.io/styleguide/include/link.png)
虽然ES6类是首选,但有些情况下ES6类可能不可行。例如:
-
如果存在或将存在子类(包括创建子类的框架),则无法立即将其更改为使用ES6类语法。如果这样的类使用ES6语法,则需要修改所有不使用ES6类语法的下游子类。
-
this
在调用超类构造函数之前需要已知值的框架,因为具有ES6超类的构造函数this
在调用super
返回之前无权访问实例值。
在所有其他方面的风格指南仍然适用于这样的代码:let
,const
,默认参数,休息和箭头的功能都应该用在适当的时候。
goog.defineClass
允许类似于ES6类语法的类类定义:
设C = goog.defineClass(S,{
/ **
* @param {string}值
* /
构造函数(值){
S.call(this,2);
/ ** @const * /
this.prop = value;
},
/ **
* @param {string} param
* @return {number}
* /
method(param){
返回0;
},
});
或者,虽然goog.defineClass
应该首选所有新代码,但也允许使用更传统的语法。
/ **
* @constructor @extends {S}
* @param {string}值
* /
函数C(值){
S.call(this,2);
/ ** @const * /
this.prop = value;
}
goog.inherits(C,S);
/ **
* @param {string} param
* @return {number}
* /
C.prototype.method = function(param){
返回0;
};
如果存在超类,则应在调用超类构造函数之后在构造函数中定义每实例属性。应该在构造函数的原型上定义方法。
正确定义构造函数原型层次结构比首次出现更难!因此,最好是使用goog.inherits
来自Closure库。
5.4.6不要prototype
直接操纵s![](https://google.github.io/styleguide/include/link.png)
class
与定义prototype
属性相比,该关键字允许更清晰,更易读的类定义。普通的实现代码没有业务操作这些对象,尽管它们仍然有用于定义5.4.5旧式类声明中定义的@record
接口和类。Mixins和修改内置对象的原型是明确禁止的。
例外:框架代码(如Polymer或Angular)可能需要使用prototype
s,并且不应采用更差的解决方法来避免这样做。
例外:在接口中定义字段(参见5.4.9接口)。
5.4.7吸气剂和固定剂![](https://google.github.io/styleguide/include/link.png)
不要使用JavaScript getter和setter属性。它们可能令人惊讶且难以推理,并且在编译器中的支持有限。改为提供普通方法。
例外:使用数据绑定框架(例如Angular和Polymer)时,可能会谨慎使用getter和setter。但请注意,编译器支持是有限的。使用它们时,必须使用get foo()
和set foo(value)
在类或对象文字中定义它们,或者如果不可能,则使用Object.defineProperties
。不要使用 Object.defineProperty
,这会干扰属性重命名。吸气剂 不得改变可观察状态。
非法:
class Foo { get next(){return this.nextId ++; } }
5.4.8覆盖toString![](https://google.github.io/styleguide/include/link.png)
该toString
方法可能被覆盖,但必须始终成功,并且永远不会有可见的副作用。
提示:特别要注意从toString调用其他方法,因为异常条件可能导致无限循环。
5.4.9接口![](https://google.github.io/styleguide/include/link.png)
接口可以用@interface
或声明@record
。声明的接口@record
可以@implements
由类或对象文字显式(即通过)或隐式实现。
接口上的所有非静态方法体必须是空块。必须在接口体之后定义字段作为存根prototype
。
例:
/ ** *可以使用的东西。 * @record * / class Frobnicator { / ** *根据给定的策略执行frobnication。 * @param {!FrobnicationStrategy}策略 * / frobnicate(策略){} } / ** @type {number}放弃之前的尝试次数。* / Frobnicator.prototype.attempts;
5.5功能![](https://google.github.io/styleguide/include/link.png)
5.5.1顶级功能![](https://google.github.io/styleguide/include/link.png)
导出的函数可以直接在exports
对象上定义,也可以在本地声明并单独导出。鼓励使用非导出功能,不应声明@private
。
例子:
/ ** @return {number} * / function helperFunction(){ 返回42; } / ** @return {number} * / function exportedFunction(){ return helperFunction()* 2; } / ** * @param {string} arg * @return {number} * / function anotherExportedFunction(arg){ return helperFunction()/ arg.length; } / ** @const * / exports = {exportedFunction,anotherExportedFunction};
/ ** @param {string} arg * / exports.foo =(arg)=> { //做一些事...... };
5.5.2嵌套函数和闭包![](https://google.github.io/styleguide/include/link.png)
函数可能包含嵌套函数定义。如果为函数指定名称很有用,则应将其分配给本地const
。
5.5.3箭头功能![](https://google.github.io/styleguide/include/link.png)
箭头函数提供了简洁的语法并修复了许多困难 this
。首选箭头函数优先于function
关键字,特别是嵌套函数(但请参见5.3.5方法简写)。
喜欢使用箭头功能f.bind(this)
,特别是结束 goog.bind(f, this)
。避免写作const self = this
。箭头函数对于回调特别有用,回调有时会传递意外的附加参数。
箭头的右侧可以是单个表达式或块。如果只有一个非破坏参数,则参数周围的括号是可选的。
提示:即使对于单参数箭头也使用括号是一个好习惯,因为如果在添加其他参数时忘记括号,代码仍然可以合理地解析(但不正确)。
5.5.4发电机![](https://google.github.io/styleguide/include/link.png)
生成器启用了许多有用的抽象,可以根据需要使用。
定义生成器函数时,在存在时*
将function
关键字附加到关键字,并使用函数名称中的空格将其分隔。当使用委托收益,附加*
的yield
关键字。
例:
/ ** @return {!Iterator <number>} * / function * gen1(){ 产量42; } / ** @return {!Iterator <number>} * / const gen2 = function *(){ yield * gen1(); } class SomeClass { / ** @return {!Iterator <number>} * / * gen(){ 产量42; } }
5.5.5参数![](https://google.github.io/styleguide/include/link.png)
必须在函数定义之前的JSDoc中使用JSDoc注释键入函数参数,但在相同签名@override
s 的情况下除外,其中省略所有类型。
参数类型可以在参数名称之前的内联中指定(如(/** number */ foo, /** string */ bar) => foo + bar
)。内联和 @param
类型注释不能在同一个函数定义中混合使用。
5.5.5.1默认参数
使用参数列表中的equals运算符允许使用可选参数。可选参数必须包含equals运算符两侧的空格,其名称与所需参数完全相同(即不带前缀 opt_
),=
在JSDoc类型中使用后缀,在必需参数之后使用,而不使用产生可观察副作用的初始值设定项。所有可选参数必须在函数声明中具有默认值,即使该值为undefined
。
例:
/ ** * @param {string}必需此参数始终是必需的。 * @param {string =} optional此参数可以省略。 * @param {!Node =} node另一个可选参数。 * / 函数maybeDoSomething(必需,可选='',node = undefined){}
谨慎使用默认参数。当有少数几个可选参数没有自然顺序时,首选解构(如在5.3.7解构中 )以创建可读API。
注意:与Python的默认参数不同,可以使用返回新的可变对象(例如{}
或[]
)的初始化器,因为每次使用默认值时都会对初始化程序进行求值,因此不会在调用之间共享单个对象。
提示:虽然包含函数调用的任意表达式可以用作初始化程序,但这些表达式应尽可能简单。避免暴露共享可变状态的初始化器,因为这很容易在函数调用之间引入意外耦合。
5.5.5.2休息参数
使用rest参数而不是访问arguments
。Rest参数...
在其JSDoc中使用前缀键入。rest参数必须是列表中的最后一个参数。...
参数名称和参数名称之间没有空格。不要命名rest参数var_args
。永远不要命名局部变量或参数arguments
,这会混淆内置名称。
例:
/ ** * @param {!Array <string>}数组这是一个普通的参数。 * @param {... number}数字参数的其余部分都是数字。 * / function variadic(array,... numbers){}
5.5.6退货![](https://google.github.io/styleguide/include/link.png)
函数返回类型必须在函数定义正上方的JSDoc中指定,除非在相同签名@override
的情况下,所有类型都被省略。
5.5.7泛型![](https://google.github.io/styleguide/include/link.png)
必要时@template TYPE
在类定义上方的JSDoc中声明泛型函数和方法。
5.5.8传播运营商![](https://google.github.io/styleguide/include/link.png)
函数调用可以使用spread运算符(...
)。Function.prototype.apply
当数组或iterable被解包为可变函数的多个参数时,首选扩展运算符。之后没有空间...
。
例:
function myFunction(... elements){} myFunction(... array,... iterable,... generator());
5.6字符串文字![](https://google.github.io/styleguide/include/link.png)
5.6.1使用单引号![](https://google.github.io/styleguide/include/link.png)
普通字符串文字用单引号('
)分隔,而不是双引号("
)。
提示:如果字符串包含单引号字符,请考虑使用模板字符串以避免必须转义引号。
普通的字符串文字可能不会跨越多行。
5.6.2模板字符串![](https://google.github.io/styleguide/include/link.png)
`
在复杂的字符串连接上使用模板字符串(分隔),尤其是涉及多个字符串文字时。模板字符串可能跨越多行。
如果模板字符串跨越多行,则不需要遵循封闭块的缩进,但是如果添加的空格无关紧要。
例:
函数算术(a,b){ return`这是一个算术运算表: $ {a} + $ {b} = $ {a + b} $ {a} - $ {b} = $ {a - b} $ {a} * $ {b} = $ {a * b} $ {a} / $ {b} = $ {a / b}`; }
5.6.3没有续行![](https://google.github.io/styleguide/include/link.png)
不要在普通或模板字符串文字中使用行连续(即,在带有反斜杠的字符串文字中结束一行)。即使ES5允许这样做,如果任何尾随空格出现在斜杠之后,它也会导致棘手的错误,并且对读者来说不那么明显。
非法:
const longString ='这是一个非常长的字符串,远远超过了80 列限制。不幸的是,它包含了很长的空间 如何连续的线条缩进。';
相反,写
const longString ='这是一个非常长的字符串,远远超过80'+ '列限制。它自'+'以来不包含很长的空间 '串联的字符串更干净。';
5.7数字文字![](https://google.github.io/styleguide/include/link.png)
数字可以用十进制,十六进制,八进制或二进制指定。使用完全相同0x
, 0o
和0b
前缀,以小写字母,十六进制,八进制,二进制和分别。除非紧接着,或x
,否则不要包括前导零 。o
b
5.8控制结构![](https://google.github.io/styleguide/include/link.png)
5.8.1 For循环![](https://google.github.io/styleguide/include/link.png)
使用ES6,语言现在有三种不同的for
循环。但是可以使用全部for
- of
尽可能优先使用循环。
for
- in
循环只能用于dict风格的对象(参见 5.3.3不要混合带引号和不带引号的键),不应该用于迭代数组。 Object.prototype.hasOwnProperty
应该在for
- in
循环中使用以排除不需要的原型属性。身高for
- of
和Object.keys
过 for
- in
如果可能的话。
5.8.2例外情况![](https://google.github.io/styleguide/include/link.png)
例外是该语言的一个重要部分,应在特殊情况发生时使用。总是抛出Error
s或子类Error
:永远不要抛出字符串文字或其他对象。new
在构建时 总是使用Error
。
自定义异常提供了一种从函数中传递其他错误信息的好方法。应该在本机Error
类型不足的任何地方定义和使用它们。
更喜欢在临时错误处理方法上抛出异常(例如传递错误容器引用类型,或返回具有错误属性的对象)。
5.8.2.1空捕获块
在应对捕获的异常时不执行任何操作是非常正确的。如果真的适合在捕获区中不采取任何行动,那么合理的原因将在评论中解释。
尝试{ return handleNumericResponse(response); } catch(ok){ //它不是数字; 那很好,继续 } return handleTextResponse(response);
非法:
尝试{ shouldFail(); 失败('预期错误'); } 捕获(预期){}
提示:与其他一些语言不同,上述模式根本不起作用,因为这会捕获所引发的错误fail
。请assertThrows()
改用。
5.8.3切换语句![](https://google.github.io/styleguide/include/link.png)
术语注意:开关块的大括号内有一个或多个语句组。每个语句组由一个或多个开关标签(case FOO:
或者default:
)组成,后跟一个或多个语句。
5.8.3.1跌倒:评论
在switch块内,每个语句组会突然终止(与 break
,return
或throw
ñ除外),或标有注释,表明执行会,也可能持续到下一个语句组。任何传达跌倒概念的评论都足够(通常// fall through
)。在switch块的最后一个语句组中不需要此特殊注释。
例:
开关(输入){ 情况1: 案例2: prepareOneOrTwo(); //摔倒 案例3: handleOneTwoOrThree(); 打破; 默认: handleLargeNumber(输入); }
5.8.3.2 default
案件存在
每个switch语句都包含一个default
语句组,即使它不包含任何代码。
5.9这个![](https://google.github.io/styleguide/include/link.png)
仅this
在类构造函数和方法中使用,或在类构造函数和方法中定义的箭头函数中使用。任何其他用法this
必须@this
在立即封闭函数的JSDoc中声明。
永远不要this
用来引用全局对象,事件的上下文,eval
事件的目标或不必要的call()
ed或apply()
ed函数。
5.10不允许的功能![](https://google.github.io/styleguide/include/link.png)
5.10.1 with![](https://google.github.io/styleguide/include/link.png)
不要使用with
关键字。它使您的代码更难理解,并且自ES5以来一直在严格模式下被禁止。
5.10.2动态代码评估![](https://google.github.io/styleguide/include/link.png)
不要使用eval
或Function(...string)
构造函数(代码加载器除外)。这些功能具有潜在的危险性,并且在CSP环境中无法正常工作。
5.10.3自动分号插入![](https://google.github.io/styleguide/include/link.png)
始终使用分号终止语句(函数和类声明除外,如上所述)。
5.10.4非标准功能![](https://google.github.io/styleguide/include/link.png)
不要使用非标准功能。这包括已删除的旧功能(例如WeakMap.clear
),尚未标准化的新功能(例如,当前的TC39工作草案,任何阶段的提案或提议但尚未完成的Web标准)或专有功能仅在某些浏览器中实现。仅使用当前ECMA-262或WHATWG标准中定义的功能。(请注意,针对特定API编写的项目,例如Chrome扩展或Node.js,显然可以使用这些API)。禁止使用非标准语言“扩展”(例如某些外部转发器提供的扩展)。
5.10.5原始类型的包装器对象![](https://google.github.io/styleguide/include/link.png)
从不使用new
对原始对象包装(Boolean
,Number
,String
, Symbol
),也不将它们包括在类型注释。
非法:
const / ** Boolean * / x = new Boolean(false); if(x)alert(typeof x); //提醒'对象' - WAT?
包装器可以被称为用于强制的函数(优选使用+
或连接空字符串)或创建符号。
例:
const / ** boolean * / x = Boolean(0); if(!x)alert(typeof x); //警告'boolean',如预期的那样
5.10.6修改内置对象![](https://google.github.io/styleguide/include/link.png)
永远不要通过向构造函数或原型添加方法来修改内置类型。避免依赖于执行此操作的库。请注意,JSCompiler的运行时库将尽可能提供符合标准的polyfill; 没有别的可以修改内置对象。
除非绝对必要,否则不要向全局对象添加符号(例如,第三方API要求)。
6命名![](https://google.github.io/styleguide/include/link.png)
6.1所有标识符共有的规则![](https://google.github.io/styleguide/include/link.png)
标识符仅使用ASCII字母和数字,并且在下面提到的少数情况下,强调并且非常少(当像Angular这样的框架需要时)美元符号。
在合理范围内尽可能给出描述性的名称。不要担心保存水平空间,因为让新代码能够立即理解您的代码更为重要。不要在项目之外使用对于读者不明确或不熟悉的缩写,也不要通过删除单词中的字母来缩写。
priceCountReader //没有缩写。 numErrors //“num”是一种普遍的惯例。 numDnsConnections //大多数人都知道“DNS”代表什么。
非法:
n //毫无意义 nErr // Ambiguous缩写。 nCompConns // Ambiguous缩写。 wgcConnections //只有您的小组知道这代表什么。 pcReader //很多东西都可以缩写为“pc”。 cstmrId //删除内部字母。 kSecondsPerDay //不要使用匈牙利表示法。
6.2按标识符类型的规则![](https://google.github.io/styleguide/include/link.png)
6.2.1包名称![](https://google.github.io/styleguide/include/link.png)
包名都是lowerCamelCase
。例如, my.exampleCode.deepSpace
但不是my.examplecode.deepspace
或my.example_code.deep_space
。
6.2.2班级名称![](https://google.github.io/styleguide/include/link.png)
写入类,接口,记录和typedef名称UpperCamelCase
。未经传播的类只是本地语言:它们没有标记@private
,因此没有使用尾随下划线命名。
类型名称通常是名词或名词短语。例如,Request
, ImmutableList
,或VisibilityMode
。另外,界面名称有时可能是形容词或形容词短语(例如Readable
)。
6.2.3方法名称![](https://google.github.io/styleguide/include/link.png)
方法名称是用lowerCamelCase
。私有方法的名称必须以尾随下划线结尾。
方法名称通常是动词或动词短语。例如,sendMessage
或 stop_
。永远不需要属性的getter和setter方法,但是如果使用它们,则应该命名getFoo
(或者可选地isFoo
或者hasFoo
为布尔值)或者setFoo(value)
用于setter。
下划线也可能出现在JsUnit测试方法名称中,以分隔名称的逻辑组件。test<MethodUnderTest>_<state>
例如,一种典型的模式testPop_emptyStack
。命名测试方法没有一种正确的方法。
6.2.4枚举名称![](https://google.github.io/styleguide/include/link.png)
枚举名称是写成的UpperCamelCase
,类似于类,通常应该是单数名词。枚举中的单个项目以 CONSTANT_CASE
。
6.2.5常量名称![](https://google.github.io/styleguide/include/link.png)
常量名称使用CONSTANT_CASE
:全部大写字母,单词用下划线分隔。没有理由使用尾随下划线来命名常量,因为私有静态属性可以由(隐式私有)模块本地替换。
6.2.5.1“常数”的定义
每个常量都是@const
静态属性或模块本地const
声明,但并非所有@const
静态属性和模块本地const
都是常量。在选择常量情况之前,请考虑该字段是否真的像一个深不可变的常量。例如,如果该实例的任何可观察状态都可以改变,那么它几乎肯定不是常量。仅仅打算永远不会改变对象通常是不够的。
例子:
//常数 const NUMBER = 5; / ** @const * / exports.NAMES = ImmutableList.of('Ed','Ann'); / ** @enum * / exports.SomeEnum = {ENUM_CONSTANT:'value'}; //不是常量 let letVariable ='non-const'; class MyClass {constructor(){/ ** @const * / this.nonStatic ='non-static'; }}; / ** @type {string} * / MyClass.staticButMutable ='not @const,可以重新分配'; const / ** Set <String> * / mutableCollection = new Set(); const / ** ImmutableSet <SomeMutableType> * / mutableElements = ImmutableSet.of(mutable); const Foo = goog.require('my.Foo'); //镜像导入的名称 const logger = log.getLogger('loggers.are.not.immutable');
常数的名称通常是名词或名词短语。
6.2.5.1本地别名
只要它们提高了对完全限定名称的可读性,就应该使用本地别名。遵循与goog.require
s(3.4 goog.require语句)相同的规则,维护别名的最后一部分。别名也可以在函数内使用。别名必须是const
。
例子:
const staticHelper = importedNamespace.staticHelper; const CONSTANT_NAME = ImportedClass.CONSTANT_NAME; const {assert,assertInstanceof} = asserts;
6.2.6非常量字段名称![](https://google.github.io/styleguide/include/link.png)
写入非常量字段名称(静态或其他)lowerCamelCase
,私有字段的尾部下划线。
这些名称通常是名词或名词短语。例如,computedValues
或index_
。
6.2.7参数名称![](https://google.github.io/styleguide/include/link.png)
参数名称是写入的lowerCamelCase
。请注意,即使参数需要构造函数,这也适用。
不应在公共方法中使用单字符参数名称。
例外:当第三方框架需要时,参数名称可以以a开头$
。此异常不适用于任何其他标识符(例如,局部变量或属性)。
6.2.8局部变量名称![](https://google.github.io/styleguide/include/link.png)
lowerCamelCase
如上所述,除了模块本地(顶级)常量外,写入局部变量名。函数作用域中的常量仍然以lowerCamelCase
。请注意,即使变量包含构造函数,lowerCamelCase也适用。
6.2.9模板参数名称![](https://google.github.io/styleguide/include/link.png)
模板参数名称应该是简洁的单字或单字母标识符,并且必须是全部大写字母,例如TYPE
或THIS
。
6.3 Camel案例:已定义![](https://google.github.io/styleguide/include/link.png)
有时将英语短语转换为驼峰大小写的方法不止一种,例如当存在首字母缩略词或类似IPv6
或 iOS的
异常构造时。为了提高可预测性,Google Style指定了以下(几乎)确定性方案。
从名称的散文形式开始:
- 将短语转换为纯ASCII并删除任何撇号。例如,
Müller的算法
可能会成为Muellers算法
。 - 将此结果划分为单词,拆分空格和任何剩余的标点符号(通常为连字符)。
- 推荐:如果任何单词已经具有常规使用的传统驼峰外观,请将其拆分为其组成部分(例如,
AdWords
成为广告词
)。请注意,像iOS
这样的单词本身并不是真正的驼峰; 它违反任何惯例,因此该建议不适用。
- 推荐:如果任何单词已经具有常规使用的传统驼峰外观,请将其拆分为其组成部分(例如,
- 现在小写所有内容(包括首字母缩略词),然后只大写第一个字符:
- ......每个字,以产生上骆驼的情况,或
- ...除了第一个之外的每个词,以产生更低的骆驼案例
- 最后,将所有单词连接成一个标识符。
请注意,原始单词的大小几乎完全被忽略。
例子:
散文形式 | 正确 | 不正确 |
---|---|---|
XML HTTP请求 |
的XmlHttpRequest | XMLHTTPRequest的 |
新客户ID |
newCustomerId | newCustomerID |
内秒表 |
innerStopwatch | innerStopWatch |
在iOS上支持IPv6? |
supportsIpv6OnIos | supportsIPv6OnIOS |
YouTube导入器 |
YouTubeImporter | YoutubeImporter * |
*可接受,但不推荐。
注意:有些单词在英语中含糊不清:例如,非空
和非空
都是正确的,因此方法名称checkNonempty和checkNonEmpty同样都是正确的。
7 JSDoc![](https://google.github.io/styleguide/include/link.png)
JSDoc用于所有类,字段和方法。
7.1一般表格![](https://google.github.io/styleguide/include/link.png)
JSDoc块的基本格式如下例所示:
/ ** *这里写了多行JSDoc文本, *正常包裹。 * @param {number} arg要做某事的数字。 * / function doSomething(arg){...}
或者在这个单行示例中:
/ ** @const @private {!Foo}一小段JSDoc。* / this.foo_ = foo;
如果单行注释溢出到多行,则必须使用多行样式/**
和*/
它们自己的行。
许多工具从JSDoc注释中提取元数据以执行代码验证和优化。因此,这些评论必须是格式良好的。
7.2降价![](https://google.github.io/styleguide/include/link.png)
JSDoc是用Markdown编写的,尽管它可能在必要时包含HTML。
请注意,自动提取JSDoc的工具(例如JsDossier)通常会忽略纯文本格式,因此如果您这样做:
/ ** *根据三个因素计算重量: *发送的项目 *收到的物品 *最后一个时间戳 * /
它会像这样出现:
根据三个因素计算权重:项目发送的项目是上次收到的时间戳
相反,写一个Markdown列表:
/ ** *根据三个因素计算重量: * - 发送的项目 * - 收到的物品 * - 上次时间戳 * /
7.3 JSDoc标签![](https://google.github.io/styleguide/include/link.png)
Google风格允许使用JSDoc标记的子集。有关完整列表,请参见 9.1 JSDoc标记参考。大多数标签必须占据自己的行,标签位于行的开头。
非法:
/ ** *“param”标记必须占用自己的行,不能合并。 * @param {number}离开@param {number}吧 * / 功能添加(左,右){...}
不需要任何附加数据简单的标记(如@private
, @const
,@final
,@export
)可以被组合到同一行,具有可选的类型在适当的时候沿。
/ ** *放置更复杂的注释(如“工具”和“模板”) *在他们自己的路线上。多个简单标签(如“导出”和“最终”) *可以合并为一行。 * @export @final * @implements {Iterable <TYPE>} * @template TYPE * / class MyClass { / ** * @param {!ObjType} obj一些对象。 * @param {number =} num可选数字。 * / 构造函数(obj,num = 42){ / ** @private @const {!Array <!ObjType | number>} * / this.data_ = [obj,num]; } }
何时组合标签或以何种顺序,但是一致,没有硬性规则。
有关JavaScript中注释类型的一般信息,请参阅 为Closure Compiler注释JavaScript和Closure Type System中的类型。
7.4换行![](https://google.github.io/styleguide/include/link.png)
换行块标记缩进四个空格。包装的描述文本可以与前面的行描述对齐,但不鼓励这种水平对齐。
/ ** *说明用于长参数/返回描述的换行。 * @param {string} foo这是一个描述太长而无法适应的参数 * 一条线。 * @return {number}这会返回描述时间过长的内容 *适合一行。 * / exports.method = function(foo){ 返回5; };
包装@fileoverview
描述时不要缩进。
7.5顶级/文件级注释![](https://google.github.io/styleguide/include/link.png)
文件可能具有顶级文件概述。版权声明,作者信息和默认可见性级别是可选的。当文件由多个类定义组成时,通常建议使用文件概述。顶级评论旨在将不熟悉代码的读者定位到此文件中。如果存在,它可以提供文件内容的描述以及任何依赖性或兼容性信息。包裹的线条不缩进。
例:
/ ** * @fileoverview文件描述,用途和信息 *关于它的依赖关系。 * @package * /
7.6课堂评论![](https://google.github.io/styleguide/include/link.png)
必须使用描述和任何模板参数,实现的接口,可见性或其他适当的标记来记录类,接口和记录。类描述应该为读者提供足够的信息,以了解如何以及何时使用该类,以及正确使用该类所需的任何其他注意事项。构造函数可能省略了文本描述。@constructor
和@extends
注释不与class
关键字一起使用, 除非该类用于声明@interface
或扩展泛型类。
/ ** *一个更酷的事件目标,可以做很酷的事情。 * @implements {Iterable <string>} * / class MyFancyTarget扩展EventTarget { / ** * @param {string} arg1使这更有趣的参数。 * @param {!Array <number>} arg2要处理的数字列表。 * / 构造函数(arg1,arg2){ // ... } }; / ** *记录也很有帮助。 * @extends {Iterator <TYPE>} * @record * @template TYPE * / class Listable { / ** @return {TYPE}要返回的行中的下一个项目。* / 下一个() {} }
7.7枚举和typedef注释![](https://google.github.io/styleguide/include/link.png)
必须记录枚举和typedef。公共枚举和typedef必须具有非空描述。可以使用前一行的JSDoc注释记录单个枚举项。
/ ** *一种有用的类型联合,经常被重用。 * @typedef {!Bandersnatch |!BandersnatchType} * / 让CoolUnionType; / ** * bandersnatches的类型。 * @enum {string} * / const BandersnatchType = { / **这种真是太酷了。* / FRUMIOUS:'太酷了', / **不那么笨拙的那种。* / MANXOME:'manxome', };
Typedef对于定义短记录类型或联合,复杂函数或泛型类型的别名非常有用。对于包含许多字段的记录类型,应避免使用Typedef,因为它们不允许记录单个字段,也不允许使用模板或递归引用。对于大型唱片类型,请选择@record
。
7.8方法和功能注释![](https://google.github.io/styleguide/include/link.png)
必须记录参数和返回类型。this
必要时应记录该类型。如果方法,参数和返回描述(但不是类型)从方法的其余部分JSDoc或其签名中显而易见,则可以省略它们。方法描述应以用第三人称声明语音写的句子开头。如果方法覆盖超类方法,则它必须包含@override
注释。如果任何类型被细化,则重写的方法必须包括all @param
和@return
注释,但如果类型完全相同则应省略它们。
/ **这是一堂课。* / someClass扩展SomeBaseClass { / ** *在MyClass的一个实例上运行并返回一些东西。 * @param {!MyClass} obj由于某种原因需要详细说明的对象 *跨越多行的解释。 * @param {!OtherClass} apparentOtherClass * @return {boolean}是否发生了什么事。 * / someMethod(obj,obviousOtherClass){...} / ** @override * / overriddenMethod(param){...} } / ** *演示顶级函数如何遵循相同的规则。这个 *制作一个数组。 * @param {TYPE} arg * @return {!Array <TYPE>} * @template TYPE * / function makeArray(arg){...}
匿名函数不需要JSDoc,但如果自动类型推断不足,则可以内联指定参数类型。
promise.then( (/ **!Array <number | string> * / items)=> { doSomethingWith(项目); return / ** @type {string} * /(items [0]); });
7.9财产评论![](https://google.github.io/styleguide/include/link.png)
必须记录属性类型。如果名称和类型提供了足够的文档来理解代码,则可以省略私有属性的描述。
公共导出的常量与属性的注释方式相同。对于@const
从具有明显已知类型的表达式初始化的属性,可以省略显式类型。
提示:如果@const
属性的类型直接来自具有声明类型的构造函数参数,或者直接来自具有声明的返回类型的函数调用,则可以将其视为“明显已知”。从更复杂的表达式分配的非const属性和属性应该明确声明它们的类型。
/** 我的课。* / class MyClass { / ** @param {string =} someString * / 构造函数(someString ='default string'){ / ** @private @const * / this.someString_ = someString; / ** @private @const {!OtherType} * / this.someOtherThing_ = functionThatReturnsAThing(); / ** *每个窗格的最大数量。 * @type {number} * / this.someProperty = 4; } } / ** *放弃之前我们会尝试的次数。 * @const * / MyClass.RETRY_COUNT = 33;
7.10输入注释![](https://google.github.io/styleguide/include/link.png)
类型的注释中发现@param
,@return
,@this
,和@type
标签,以及可选的@const
,@export
和任何知名度的标签。附加到JSDoc标记的类型注释必须始终用大括号括起来。
7.10.1可空性![](https://google.github.io/styleguide/include/link.png)
类型系统分别定义修饰符!
和?
非null和可空。原始类型(undefined
,string
,number
,boolean
, symbol
,和function(...): ...
),并记录文字({foo: string, bar: number}
)默认情况下非空。不要!
为这些类型添加显式。对象类型(Array
,Element
,MyClass
,等等)是通过缺省为空的,但不能从作为名称被立即分辨@typedef
“d到一个非空逐默认类型。因此,除了基元和记录文字之外的所有类型都必须使用?
或明确注释或!
指示它们是否可为空。
7.10.2类型转换![](https://google.github.io/styleguide/include/link.png)
在类型检查不能准确推断表达式类型的情况下,可以通过添加类型注释注释并将表达式括在括号中来收紧类型。请注意,括号是必需的。
/ ** @type {number} * /(x)
7.10.3模板参数类型![](https://google.github.io/styleguide/include/link.png)
始终指定模板参数。这样编译器可以做得更好,它使读者更容易理解代码的作用。
坏:
const / **!Object * / users = {}; const / **!Array * / books = []; const / **!Promise * / response = ...;
好:
const / **!Object <string,!User> * / users = {}; const / **!Array <string> * / books = []; const / **!承诺<!Response> * / response = ...; const / **!Promise <undefined> * / thisPromiseReturnsNothingButParameterIsStillUseful = ...; const / **!Object <string,*> * / mapOfEverything = {};
不应使用模板参数的情况:
Object
用于类型层次结构而不是类似地图的结构。
7.11可见性注释![](https://google.github.io/styleguide/include/link.png)
可见性注释(@private
,, )可以在块中指定@package
,@protected
也可以@fileoverview
在任何导出的符号或属性上指定。不要指定局部变量的可见性,无论是在函数内还是在模块的顶层。所有@private
名称必须以下划线结尾。
8政策![](https://google.github.io/styleguide/include/link.png)
8.1 Google风格未指定的问题:保持一致!![](https://google.github.io/styleguide/include/link.png)
对于任何未通过此规范明确解决的样式问题,更喜欢执行同一文件中的其他代码已经在执行的操作。如果这不能解决问题,请考虑模拟同一包中的其他文件。
8.2编译器警告![](https://google.github.io/styleguide/include/link.png)
8.2.1使用标准警告集![](https://google.github.io/styleguide/include/link.png)
尽可能使用项目--warning_level=VERBOSE
。
8.2.2如何处理警告![](https://google.github.io/styleguide/include/link.png)
在做任何事情之前,请确保您完全理解警告告诉您的内容。如果您不肯定为什么会出现警告,请寻求帮助。
理解警告后,请按顺序尝试以下解决方案:
- 首先,修复它或解决它。强烈尝试实际处理警告,或找到另一种方法来完成完全避免这种情况的任务。
- 否则,确定它是否是误报警。如果您确信警告无效且代码实际上是安全和正确的,请添加注释以使读者相信这一事实并应用
@suppress
注释。 - 否则,请留下TODO评论。这是最后的选择。如果这样做,请不要取消警告。警告应该是可见的,直到可以正确处理。
8.2.3在最合理的范围内抑制警告![](https://google.github.io/styleguide/include/link.png)
警告在最合理的范围内被抑制,通常是单个局部变量或非常小的方法。通常,仅为此原因提取变量或方法。
例
/ ** @suppress {uselessCode}无法识别'use asm'声明* / function fn(){ '使用asm'; 返回0; }
即使是一个类中的大量抑制仍然比将整个类隐藏到这种类型的警告更好。
8.3弃用![](https://google.github.io/styleguide/include/link.png)
标记已弃用的方法,类或带@deprecated
注释的接口。弃用评论必须包含简单明了的方向,以便人们修复其呼叫站点。
8.4不适用于Google风格的代码![](https://google.github.io/styleguide/include/link.png)
您偶尔会遇到代码库中不符合Google风格的文件。这些可能来自收购,或者可能是在Google Style在某个问题上占据一席之前编写的,或者可能由于任何其他原因而处于非Google风格。
8.4.1重新格式化现有代码![](https://google.github.io/styleguide/include/link.png)
更新现有代码的样式时,请遵循以下准则。
- 不需要更改所有现有代码以符合当前样式指南。重新格式化现有代码是代码流失和一致性之间的权衡。样式规则随着时间的推移而发展,这些调整以保持合规性会产生不必要的流失。但是,如果对文件进行了重大更改,则预计该文件将采用Google风格。
- 注意不要让机会主义风格修复混淆CL的焦点。如果您发现自己进行了很多样式更改,这些更改对于CL的核心焦点并不重要,请将这些更改提升为单独的CL。
8.4.2新增代码:使用Google Style![](https://google.github.io/styleguide/include/link.png)
全新文件使用Google Style,无论同一包中其他文件的样式选择如何。
将新代码添加到非Google风格的文件时,建议首先重新格式化现有代码,但需遵循8.4.1重新格式化现有代码中的建议 。
如果未执行此重新格式化,则新代码应尽可能与同一文件中的现有代码保持一致,但不得违反样式指南。
8.5本地风格规则![](https://google.github.io/styleguide/include/link.png)
团队和项目可能会采用除本文档之外的其他样式规则,但必须接受清理更改可能不遵守这些附加规则,并且不得因违反任何其他规则而阻止此类清理更改。谨防过多的规则,没有任何目的。样式指南并不寻求在每种可能的场景中定义样式,也不应该。
8.6生成的代码:大多数是免除的![](https://google.github.io/styleguide/include/link.png)
构建过程生成的源代码不需要采用Google Style。但是,任何从手写源代码引用的生成标识符都必须遵循命名要求。作为特殊例外,允许此类标识符包含下划线,这可能有助于避免与手写标识符冲突。
9附录![](https://google.github.io/styleguide/include/link.png)
9.1 JSDoc标记引用![](https://google.github.io/styleguide/include/link.png)
JSDoc在JavaScript中有多种用途。除了用于生成文档之外,它还用于控制工具。最着名的是Closure Compiler类型注释。
9.1.1键入注释和其他Closure Compiler注释![](https://google.github.io/styleguide/include/link.png)
Closure编译器使用的JSDoc文档在闭包编译器的注释JavaScript和闭包类型系统中的类型中进行了描述 。
9.1.2文档注释![](https://google.github.io/styleguide/include/link.png)
除了为Closure Compiler注释JavaScript中描述的JSDoc之外,以下标记是常见的,并且受到各种文档生成工具(例如JsDossier)的良好支持,仅用于文档目的。
标签 | 模板和示例 | 描述 |
---|---|---|
@author 要么 @owner |
@author username@google.com (First Last)
例如: / ** * @fileoverview用于处理textareas的实用程序。 * @author kuth@google.com(Uthur Pendragon) * / |
记录文件的作者或测试的所有者,通常仅在@fileoverview 评论中使用。@owner 单元测试仪表板使用该标记来确定谁拥有测试结果。
不建议。 |
@bug |
@bug bugnumber
例如: / ** @bug 1234567 * / function testSomething(){ // ... } / ** * @bug 1234568 * @bug 1234569 * / function testTwoBugs(){ // ... } |
指示给定测试函数回归测试的错误。
多个错误应该各自都有自己的 |
@code |
{@code ...}
例如: / ** *移动到选择中的下一个位置。 *当它出现{@code goog.iter.StopIteration}时 *通过范围的结束。 * @return {!Node}下一个位置的节点。 * / goog.dom.RangeIterator.prototype.next = function(){ // ... }; |
表示JSDoc描述中的术语是代码,因此可以在生成的文档中正确格式化。 |
@see |
@see Link
例如: / ** *鲁莽地添加单个项目。 * @see #addSafely * @see goog.Collect * @see goog.RecklessAdder #add * / |
引用查找到另一个类函数或方法。 |
@supported |
@supported Description
例如: / ** * @fileoverview事件管理器 *提供抽象的接口 *浏览器的事件系统。 * @supported IE10 +,Chrome,Safari * / |
在fileoverview中用于指示文件支持的浏览器。 |
@desc |
@desc Message description
例如: / ** @desc通知用户他们的帐户已创建。* / exports.MSG_ACCOUNT_CREATED = goog.getMsg( '您的帐户已经创建成功。'); |
您还可以在第三方代码中看到其他类型的JSDoc注释。这些注释出现在JSDoc Toolkit标记参考中,但不被视为有效Google风格的一部分。
9.1.3特定于框架的注释![](https://google.github.io/styleguide/include/link.png)
以下注释特定于特定框架。
骨架 | 标签 | 文档 |
---|---|---|
角度1 | @ngInject |
|
聚合物 | @polymerBehavior |
https://github.com/google/closure-compiler/wiki/Polymer-Pass |
9.1.4关于标准Closure Compiler注释的注释![](https://google.github.io/styleguide/include/link.png)
以下标记过去是标准的,但现在已弃用。
标签 | 模板和示例 | 描述 |
---|---|---|
@expose |
@expose |
已过时。不使用。使用@export 和/或@nocollapse 代替。 |
@inheritDoc |
@inheritDoc |
已过时。不使用。请@override 改用。 |
9.2常被误解的风格规则![](https://google.github.io/styleguide/include/link.png)
以下是关于Google Style for JavaScript的一些鲜为人知或常被误解的事实的集合。(以下是真实陈述;这不是神话
列表。
)
@author
源文件中既不需要版权声明也不需要信用。(两者都没有明确推荐。)- 除了第一个构造函数(5.4.1构造函数)之外,没有
强硬的
规则来管理如何对类的成员进行排序(5.4类)。 - 空块通常可以简洁地表示为
{}
,如(4.1.3空块:可能简明)中所述。 - 换行的主要指令是:更倾向于在更高的句法层面打破(4.5.1在哪里打破)。
- 字符串文字,注释和Javadoc中允许使用非ASCII字符,实际上,当它们使代码比同等的Unicode转义符(2.3.3非ASCII字符)更容易阅读时,建议使用非ASCII字符。
9.3与风格相关的工具![](https://google.github.io/styleguide/include/link.png)
存在以下工具以支持Google Style的各个方面。
9.3.1闭包编译器![](https://google.github.io/styleguide/include/link.png)
该程序执行类型检查和其他检查,优化和其他转换(例如ECMAScript 6到ECMAScript 5代码降低)。
9.3.2 clang-format
![](https://google.github.io/styleguide/include/link.png)
该程序将JavaScript源代码重新格式化为Google Style,并且还遵循一些非必需但经常可读性增强的格式化实践。
clang-format
不需要。允许作者改变其输出,允许审稿人要求进行此类更改; 争议以通常的方式解决。但是,子树可以选择在本地选择加入。
9.3.3 Closure编译器linter![](https://google.github.io/styleguide/include/link.png)
该程序检查各种失误和反模式。
9.3.4一致性框架![](https://google.github.io/styleguide/include/link.png)
JS一致性框架是一个工具,它是Closure Compiler的一部分,它为开发人员提供了一种简单的方法来指定一组额外的检查,以便在标准检查之上对其代码库运行。例如,一致性检查可以禁止访问某个属性,或者调用某个函数,或者丢失类型信息(未知数)。
这些规则通常用于强制执行关键限制(例如定义可能破坏代码库的全局变量)和安全模式(例如使用 eval
或分配innerHTML
),或者更松散地提高代码质量。
有关其他信息,请参阅JS一致性框架的官方文档 。
9.4传统平台的例外情况![](https://google.github.io/styleguide/include/link.png)
9.4.1概述![](https://google.github.io/styleguide/include/link.png)
本节描述了当代码作者无法使用现代ECMAScript 6语法时要遵循的异常和其他规则。如果无法使用ECMAScript 6语法,则需要使用推荐样式的例外情况,并在此处概述:
var
允许使用声明- 使用
arguments
被允许 - 允许使用没有默认值的可选参数
9.4.2使用 var
![](https://google.github.io/styleguide/include/link.png)
9.4.2.1 var
声明不是块范围的
var
声明的范围限定在最近的封闭函数,脚本或模块的开头,这可能会导致意外行为,尤其是var
在循环内部引用声明的函数闭包时。以下代码给出了一个示例:
for(var i = 0; i <3; ++ i){ var iteration = i; setTimeout(function(){console.log(iteration);},i * 1000); } // log 2,2,2 - NOT 0,1,2 //因为`iteration`是函数范围的,不是循环的本地。
9.4.2.2声明变量尽可能接近首次使用
尽管var
声明的范围限定在封闭函数的开头,但var
为了便于阅读,声明应尽可能接近它们的首次使用。但是,var
如果在块外部引用该变量,则不要在块中放置声明。例如:
function sillyFunction(){ var count = 0; for(var x in y){ //“count”可以在这里声明,但不要这样做。 计数++; } console.log(在y'中计算+'项目); }
9.4.2.3使用@const作为常量变量
对于const
将使用关键字的全局声明,如果可用,则var
使用@const 注释声明(对于局部变量,这是可选的)。
9.4.3不要使用块作用域函数声明![](https://google.github.io/styleguide/include/link.png)
难道不是这样做:
if(x){ function foo(){} }
虽然在ECMAScript 6支持功能声明之前实现的大多数JavaScript VM都没有标准化。实现彼此不一致,并且与块范围函数声明的现在标准ECMAScript 6行为不一致。ECMAScript 5和previous仅允许在脚本或函数的根语句列表中进行函数声明,并在严格模式下在块作用域中明确禁止它们。
要获得一致的行为,请使用var
带有函数表达式的初始化来定义块中的函数:
if(x){ var foo = function(){}; }
9.4.4使用goog.provide
/进行依赖管理goog.require
![](https://google.github.io/styleguide/include/link.png)
goog.provide
已弃用。goog.module
即使在具有现有goog.provide
用途的项目中,也应使用所有新文件。以下规则仅适用于预先存在的goog.provide文件。
9.4.4.1摘要
- 将所有
goog.provide
s放在第一位,goog.require
第二位。单独提供需要空行。 - 按字母顺序对条目排序(首先是大写)。
- 不要包装
goog.provide
和goog.require
陈述。如有必要,可超过80列。 - 仅提供顶级符号。
截至2016年10月,goog.provide
/ goog.require
dependency管理已弃用。所有新文件,即使在使用goog.provide
旧文件的项目中,也应该使用 goog.module
。
goog.provide
语句应该组合在一起并放在第一位。所有 goog.require
陈述都应遵循。这两个列表应该用空行分隔。
类似其他语言的导入语句,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
dependency管理的代码中对命名空间符号的引用。
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; //构造函数声明后别名新类型。 my.module.SomeType = function(){...}; var SomeType = my.module.SomeType; //像往常一样在原型上声明方法: SomeType.prototype.findButton = function(){ //上面有别名的按钮。 this.button = new Button(dom.getElement('my-button')); }; ... }); // goog.scope