前言相当不错的 Javascript 编程风格规范,建议大家采用此规范编写 Javascript。原文链接:
http://dojotoolkit.org/developer/StyleGuide 。
翻译(Translated by):feelinglucky{at}gmail.com,转载请注明出处、作者和翻译者,谢谢配合。
本文地址:
http://code.google.com/p/grace/wiki/DojoStyle 。
序
Any violation to this guide is allowed if it enhances readability.
所有的代码都要变成可供他人容易阅读的。
快读参考
核心 API 请使用下面的风格:
[table][tr][td]
结构 [/td][td]
规则 [/td][td]
注释 [/td][/tr][tr][td]模块[/td][td]小写[/td][td]不要使用多重语义(Never multiple words)[/td][/tr][tr][td]类[/td][td]骆驼[/td][td] [/td][/tr][tr][td]公有方法[/td][td]混合[/td][td]其他的外部调用也可以使用 lower_case(),这样的风格[/td][/tr][tr][td]公有变量[/td][td]混合[/td][td] [/td][/tr][tr][td]常量[/td][td]骆驼 或 大写 [/td][td] [/td][/tr][/table]
下面的虽然不是必要的,但建议使用:
[table][tr][td]
结构 [/td][td]
规则 [/td][/tr][tr][td]私有方法[/td][td]混合,例子:
_mixedCase[/td][/tr][tr][td]私有变量[/td][td]混合,例子:
_mixedCase[/td][/tr][tr][td]方法(method)参数[/td][td]混合,例子:
_mixedCase, mixedCase[/td][/tr][tr][td]本地(local)变量[/td][td]混合,例子:
_mixedCase, mixedCase[/td][/tr][/table]
命名规范
[li]变量名称 必须为 小写字母。 [/li][li]类的命名使用骆驼命名规则,例如: Account, EventHandler[/pre][/li][li]常量 必须 在对象(类)或者枚举变量的前部声明。枚举变量的命名必须要有实际的意义,并且其成员 必须 使用骆驼命名规则或使用大写: var NodeTypes = {
Element : 1,
DOCUMENT: 2
}[/pre][/li][li]简写单词 不能使用 大写名称作为变量名: getInnerHtml(), getXml(), XmlDocument[/pre][/li][li]方法的命令 必须 为动词或者是动词短语: obj.getSomeValue()[/pre][/li][li]公有类的命名 必须 使用混合名称(mixedCase)命名。 [/li][li]CSS 变量的命名 必须 使用其对应的相同的公共类变量。 [/li][li]私有类的变量属性成员 必须 使用混合名称(mixedCase)命名,并前面下下划线(_)。例如: var MyClass = function(){
var _buffer;
this.doSomething = function(){
};
}[/pre][/li][li]变量如果设置为私有,则前面 必须 添加下划线。 this._somePrivateVariable = statement;[/pre][/li][li]通用的变量 必须 使用与其名字一致的类型名称: setTopic(topic) // 变量 topic 为 Topic 类型的变量[/pre][/li][li]所有的变量名 必须 使用英文名称。 [/li][li]变量如有较广的作用域(large scope),必须使用全局变量;此时可以设计成一个类的成员。相对的如作用域较小或为私有变量则使用简洁的单词命名。 [/li][li]如果变量有其隐含的返回值,则避免使用其相似的方法: getHandler(); // 避免使用 getEventHandler()[/pre][/li][li]公有变量必须清楚的表达其自身的属性,避免字义含糊不清,例如: MouseEventHandler,而非 MseEvtHdlr。[/pre][blockquote]请再次注意这条规定,这样做得的好处是非常明显的。它能明确的表达表达式所定义的含义。例如: dojo.events.mouse.Handler // 而非 dojo.events.mouse.MouseEventHandler[/pre][/blockquote][/li][li]类/构造函数 可以使用 扩展其基类的名称命名,这样可以正确、迅速的找到其基类的名称: EventHandler
UIEventHandler
MouseEventHandler[/pre][blockquote]基类可以在明确描述其属性的前提下,缩减其命名: MouseEventHandler as opposed to MouseUIEventHandler.[/pre][/blockquote][/li]
特殊命名规范
[li]术语 "get/set" 不要和一个字段相连,除非它被定义为私有变量。 [/li][li]前面加 "is" 的变量名 应该 为布尔值,同理可以为 "has", "can" 或者 "should"。 [/li][li]术语 "compute" 作为变量名应为已经计算完成的变量。 [/li][li]术语 "find" 作为变量名应为已经查找完成的变量。 [/li][li]术语 "initialize" 或者 "init" 作为变量名应为已经实例化(初始化)完成的类或者其他类型的变量。 [/li][li]UI (用户界面)控制变量应在名称后加控制类型,例如: leftComboBox, TopScrollPane。 [/li][li]复数必须有其公共的名称约定(原文:Plural form MUST be used to name collections)。 [/li][li]带有 "num" 或者 "count" 开头的变量名约定为数字(对象)。 [/li][li]重复变量建议使用 "i", "j", "k" (依次类推)等名称的变量。 [/li][li]补充用语必须使用补充词,例如: get/set, add/remove, create/destroy, start/stop, insert/delete, begin/end, etc. [/li][li]能缩写的名称尽量使用缩写。 [/li][li]避免产生歧义的布尔变量名称,例如: isNotError, isNotFound 为非法[/pre][/li][li]错误类建议在变量名称后加上 "Exception" 或者 "Error"。 [/li][li]方法如果返回一个类,则应该在名称上说明返回什么;如果是一个过程,则应该说明做了什么。 [/li]
文件
[li]缩进请使用 4 个空白符的制表位。 [/li][li]如果您的编辑器支持 文件标签_(file tags),请加添如下的一行使我们的代码更容易阅读: // vim:ts=4:noet:tw=0:[/pre]译注:老外用 VIM 编辑器比较多,此条可以选择遵循。
[li]代码折叠必须看起来是完成并且是合乎逻辑的:
var someExpression = Expression1
+ Expression2
+ Expression3;
var o = someObject.get(
Expression1,
Expression2,
Expression3
);[/pre][blockquote]注:表达式的缩进与变量声明应为一致的。 [/blockquote][/li]
[/li]
[blockquote]注:函数的参数应采用明确的缩进,缩进规则与其他块保持一致。 [/blockquote]
变量
[li]变量必须在声明初始化以后才能使用,即便是 NULL 类型。 [/li][li]变量不能产生歧义。 [/li][li]相关的变量集应该放在同一代码块中,非相关的变量集不应该放在同一代码块中。 [/li][li]变量应该尽量保持最小的生存周期。 [/li][li]循环/重复变量的规范: [li]只有循环控制块的话,则必须使用 FOR 循环。 [/li][li]循环变量应该在循环开始前就被初始化;如使用 FOR 循环,则使用 FOR 语句初始化循环变量。 [/li][li]"do ... while" 语句是被允许的。 [/li][li]"break" 和 "continue" 语句仍然允许使用(但请注意)。 [/li]
[/li][li]条件表达式 [li]应该尽量避免复杂的条件表达式,如有必要可以使用临时布尔变量。 [/li][li]The nominal case SHOULD be put in the "if" part and the exception in the "else" part of an "if" statement. [/li][li]应避免在条件表达式中加入块。 [/li]
[/li][li]杂项 [li]尽量避免幻数(Magic numbers),他们应该使用常量来代替。 [/li][li]浮点变量必须指明小数点后一位(即使是 0)。 [/li][li]浮点变量必须指明实部,即使它们为零(使用 0. 开头)。 [/li]
[/li]
布局
块
[li]普通代码段 应该 看起来如下: while (!isDone){
doSomething();
isDone = moreToDo();
}[/pre][/li][li]IF 语句 应该 看起来像这样: if (someCondition){
statements;
} else if (someOtherCondition){
statements;
} else {
statements;
}[/pre][/li][li]FOR 语句 应该 看起来像这样: for (initialization; condition; update){
statements;
}[/pre][/li][li]WHILE 语句 应该 看起来像这样: while (!isDone) {
doSomething();
isDone = moreToDo();
}[/pre][/li][li]DO ... WHILE 语句 应该 看起来像这样: do {
statements;
} while (condition);[/pre][/li][li]SWITCH 语句 应该 看起来像这样: switch (condition) {
case ABC:
statements;
// fallthrough
case DEF:
statements;
break;
default:
statements;
break;
}[/pre][/li][li]TRY ... CATCH 语句 应该 看起来像这样: try {
statements;
} catch(ex) {
statements;
} finally {
statements;
}[/pre][/li][li]单行的 IF - ELSE,WHILE 或者 FOR 语句也 必须 加入括号,不过他们可以这样写: if (condition){ statement; }
while (condition){ statement; }
for (intialization; condition; update){ statement; }[/pre][/li]
空白
[li]操作符 建议 使用空格隔开(包括三元操作符)。 [/li][li]下面的关键字 避免使用 空白隔开: [li]break [/li][li]catch [/li][li]continue [/li][li]do [/li][li]else [/li][li]finally [/li][li]for [/li][li]function (如果为匿名函数,例如:var foo = function(){}; ) [/li][li]if [/li][li]return [/li][li]switch [/li][li]this [/li][li]try [/li][li]void [/li][li]while [/li][li]with [/li]
[/li][li]下面的关键字必须使用空白隔开:
[li]case [/li][li]default [/li][li]delete [/li][li]function (如果为申明,例如:function foo(){}; ) [/li][li]in [/li][li]instanceof [/li][li]new [/li][li]throw [/li][li]typeof [/li][li]var [/li]
[/li][li]
逗号(,) 建议 使用空白隔开。 [/li][li]
冒号(:) 建议 使用空白隔开。 [/li][li]
点(.) 在后部
建议 使用空白隔开。 [/li][li]
点(.) 避免 在前部使用空白。 [/li][li]
函数调用和方法 避免 使用空白,例如:
doSomething(someParameter); // 而非 doSomething (someParameter) [/li][li]
逻辑块 之间使用空行。 [/li][li]
声明 建议 对齐使其更容易阅读。 [/li]
注释
[li]生涩的代码就 没有必要 添加注释了,首先您需要 重写 它们。 [/li][li]所有的注释请使用英文。 [/li][li]从已解决的方案到未开发的功能,注释 必须 与代码相关。 [/li][li]大量的变量申明后 必须 跟随一段注释。 [/li][li]注释需要说明的是代码段的用处,尤其是接下来的代码段。 [/li][li]注释 没有必要 每行都添加。 [/li]
文档
下面提供了一些基本的函数或者对象的描述方法:
[li]总结(summary): 简短的表述此函数或者对象实现的目的 [/li][li]描述(description): 对于此函数或者类的简短的描述 [/li][li]返回(return): 描述此函数返回什么(并不包括返回类型) [/li]
基本函数信息
function(){
// summary: Soon we will have enough treasure to rule all of New Jersey.
// description: or we could just get a new roomate.
// Look, you go find him. He don't yell at you.
// All I ever try to do is make him smile and sing around
// him and dance around him and he just lays into me.
// He told me to get in the freezer 'cause there was a carnival in there.
// returns: Look, a Bananarama tape!
}[/pre]
对象函数信息
没有返回值描述
{
// summary: Dingle, engage the rainbow machine!
// description:
// Tell you what, I wish I was--oh my g--that beam,
// coming up like that, the speed, you might wanna adjust that.
// It really did a number on my back, there. I mean, and I don't
// wanna say whiplash, just yet, cause that's a little too far,
// but, you're insured, right?
}[/pre]
函数的声明
在有的情况下,对于函数的调用和声明是隐义(invisible)的。在这种情况下,我们没有办法在函数中加入说明等(供程序调用)。如果您遭遇了这种情况,您可以使用一个类来封装函数。
注:此此方法只能在函数没有初始化的参数情况下。如过不是,则它们会被忽略。
dojo.declare(
"foo",
null,
{
// summary: Phew, this sure is relaxing, Frylock.
// description:
// Thousands of years ago, before the dawn of
// man as we knew him, there was Sir Santa of Claus: an
// ape-like creature making crude and pointless toys out
// of dino-bones, hurling them at chimp-like creatures with
// crinkled hands regardless of how they behaved the
// previous year.
// returns: Unless Carl pays tribute to the Elfin Elders in space.
}
);[/pre]
参数
[li]简单类型 [blockquote]简单的类型的参数可以直接在函数参数定义中注释说明。 function(/*String*/ foo, /*int*/ bar)...[/pre][/blockquote][/li][li]可变类型参数 [blockquote]下面是几个修饰符供参考: [/blockquote][li]? 可选参数 [/li][li]... 说面参数范围不确定 [/li][li][] 数组 function(/*String?*/ foo, /*int...*/ bar, /*String[]*/ baz)...[/pre][/li]
[/li][li]全局参数描述 [blockquote]如果你想增加一个描述,你可以将它们移至初始化块。 [/blockquote][/li][blockquote]基本信息格式为:
*关键字* 描述字段 (
*key* Descriptive sentence) [/blockquote][blockquote]参数和变量的格式为:
*关键字* ~*类型*~ 描述字段 (
*key* ~*type*~ Descriptive sentence) [/blockquote][blockquote]注:
*关键字* 和 ~*类型*~ 可以使用任何字母和数字表述。 function (foo, bar) {
// foo: String
// used for being the first parameter
// bar: int
// used for being the second parameter
}[/pre][/blockquote]
变量
由于实例变量、原型变量和外部变量的声明是一致的,所以有很多的方法声明、修改变量。具体的如何定义和定位应在变量最先出现的位置指明变量的名称、类型、作用域等信息。
function foo() {
// myString: String
// times: int
// How many times to print myString
// separator: String
// What to print out in between myString*
this.myString = "placeholder text";
this.times = 5;
}
foo.prototype.setString = function (myString) {
this.myString = myString;
}
foo.prototype.toString = function() {
for(int i = 0; i < this.times; i++) {
dojo.debug(this.myString);
dojo.debug(foo.separator);
}
}
foo.separator = "=====";[/pre]
对象中的变量注释
应使用和对象值和方法一致的标注方式,比如在他们声明的时候:
{
// key: String
// A simple value
key: "value",
// key2: String
// Another simple value
}[/pre]
返回值
因为函数可以同时返回多个不同(类型)的值,所以应每个返回值之后加入返回类型的注释。注释在行内注释即可,如果所有的返回值为同一类型,则指明返回的类型;如为多个不同的返回值,则标注返回类型为"mixed"。
function() {
if (arguments.length) {
return "You passed argument(s)"; // String
} else {
return false; // Boolean
}
}[/pre]
伪代码(有待讨论)
有时候您需要在函数或者类中添加对于此函数和类的功能性流程描述。如果您打算这样做,您可以使用
/*======== (= 字符最好出现 5 次或者更多),这样做的好处就是可以不用将这些东西加入代码(译注:原作者的意思可能为代码管理系统)。
这样看起来在
/*===== 和
=====*/ 会有非常长的一段注释,等待功能调整完毕以后就可以考虑是否删除。
/*=====
module.pseudo.kwArgs = {
// url: String
// The location of the file
url: "",
// mimeType: String
// text/html, text/xml, etc
mimeType: ""
}
=====*/
function(/*module.pseudo.kwArgs*/ kwArgs){
dojo.debug(kwArgs.url);
dojo.debug(kwArgs.mimeType);
}[/pre]