JavaSciprt编码规范-2
JS编码规范:
(一)
这是一套适用于JavaScript程序的编码规范。它基于Sun的java程序编码规范。但进行了大幅度的修改, 因为JavaScript不是Java。
软件的长期价值直接源于其编码质量。在它的整个生命周期里,一个程序可能会被许多人阅读或修改。如果一个程序可以清晰的展现出它的结构和特征,那就能减少在以后对其进行修改时出错的可能性。
编程规范可以帮助程序员们增加程序的健壮性。
所有的JavaScript代码都是暴露给公众的。所以我们更应该保证其质量。
保持整洁很重要。
JavaScript文件
JavaScript程序应独立保存在后缀名为.js的文件中。
JavaScript代码不应该被包含在HTML文件中,除非这是段特定只属于此部分的代码。在HTML中的JavaScript代码会明显增加文件大小,而且也不能对其进行缓存和压缩。
<script src=
filename.js>
应尽量放到body的后面。这样可以减少因为载入script而造成其他页面内容载入也被延迟的问题。也没有必要使用language或者type属性。MIME类型是由服务器而非scripttag来决定的。
缩进
缩进的单位为四个空格。避免使用Tab键来缩进(即使现在已经是21世纪了),也始终没有个统一的Tab长短标准。虽然使用空格会增加文件的大小,但在局域网中几乎可以忽略,且在最小化过程中也可被消除掉。
每行长度
避免每行超过80个字符。当一条语句一行写不下时,请考虑折行。在运算符号,最好是逗号后换行。在运算符后换行可以减少因为复制粘贴产生的错误被分号掩盖的几率。下一行应该缩进8个空格。
注释
不要吝啬注释。给以后需要理解你的代码的人们(或许就是你自己)留下信息是非常有用的。注释应该和它们所注释的代码一样是书写良好且清晰明了。偶尔的小幽默就更不错了。记得要避免冗长或者情绪化。
及时地更新注释也很重要。错误的注释会让程序更加难以阅读和理解。
让注释有意义。重点在解释那些不容易立即明白的逻辑上。不要把读者的时间浪费在阅读类似于:
i = 0; //让i等于0
使用单行注释。块注释用于注释正式文档和无用代码。
变量声明
所有的变量必须在使用前进行声明。JavaScript并不强制必须这么做,但是这么做可以让程序易于阅读,且也容易发现那些没声明的变量(它们会被编译成全局变量)。
将var语句放在函数的首部。
最好把每个变量的声明语句单独放到一行,并加上注释说明。所有变量按照字母排序。
var currentEntry; // 当前选择项 var level; // 缩进程度 var size; // 表格大小
JavaScript没有块范围,所以在块里面定义变量很容易引起C/C++/Java程序员们的误解。在函数的首部定义所有的变量。
尽量减少全局变量的使用。不要让局部变量覆盖全局变量。
函数声明
所有的函数在使用前进行声明。 内函数的声明跟在var语句的后面。这样可以帮助判断哪些变量是在函数范围内的。
函数名与((左括号)之间不应该有空格。)(右括号)与 开始程序体的{(左大括号)之间应插入一个空格。函数程序体应缩进四个空格。}(右大括号)与声明函数的那一行代码头部对齐。
function outer(c, d) { var e = c * d; function inner(a, b) { return (e * a) + b; } return inner(0, 1); }
下面这种书写方式可以在JavaScript中正常使用,因为在JavaScript中,函数和对象的声明可以放到任何表达式允许的地方。且它让内联函数和混合结构具有最好的可读性。
function getElementsByClassName(className) { var results = []; walkTheDOM(document.body, function (node) { var a; // 类名数组 var c = node.className; // 节点的类名 var i; // 循环计数器 // If the node has a class name, then split it into a list of simple names. // If any of them match the requested name, then append the node to the set of results. if (c) { a = c.split(' '); for (i = 0; i < a.length; i += 1) { if (a[i] === className) { results.push(node); break; } } } }); return results; }
如果函数是匿名函数,则在function和((左括号)之间应有一个空格。如果省略了空格,否则会让人感觉函数名叫作 function。
div.onclick = function (e) { return false; }; that = { method: function () { return this.datum; }, datum: 0 };
尽量不使用全局函数。
When a function is to be invoked immediately, the entire invocation expression should be wrapped in parens so that it is clear that the value being produced is the result of the function and not the function itself.
var collection = (function () { var keys = [], values = []; return { get: function (key) { var at = keys.indexOf(key); if (at >= 0) { return value[at]; } }, set: function (key, value) { var at = keys.indexOf(key); if (at < 0) { at = keys.length; } keys[at] = key; value[at] = value; }, remove: function (key) { var at = keys.indexOf(key); if (at >= 0) { keys.splice(at, 1); value.splice(at, 1); } } }; }());
命名
变量名应由26个大小写字母(A..Z,a..z),10个数字(0..9),和_(下划线)组成。避免使用国际化字符(如中文),因为它们不是在任何地方都可以被方便的阅读和理解。不要在命名中使用$(美元符号)或者(反斜杠)。
不要把_(下划线)作为变量名的第一个字符。它有时用来表示私有变量,但实际上JavaScript并没提供私有变量的功能。如果私有变量很重要, 那么使用私有成员的形式。应避免使用这种容易让人误解的命名习惯。
大多数的变量名和方法命应以小写字母开头。
必须与new共同使用的构造函数名应以大写字母开头。当new被省略时JavaScript不会有任何编译错误或运行错误抛出。忘记加new时会让不好的事情发生(比如被当成一般的函数),所以大写构造函数名是我们来尽量避免这种情况发生的唯一办法。
全局变量应该全部大写。(JavaScript没有宏或者常量,所以不会因此造成误会)
语句
简单语句
每一行最多只包含一条语句。把;(分号)放到每条简单语句的结尾处。注意一个函数赋值或对象赋值语句也是赋值语句,应该以分号结尾。
JavaScript可以把任何表达式当作一条语句。这很容易隐藏一些错误,特别是误加分号的错误。只有在赋值和调用时,表达式才应被当作一条单独的语句。
复合语句
复合语句是被包含在{ }(大括号)的语句序列。
- 被括起的语句必须多缩进四个空格。
- {(左大括号)应在复合语句其实行的结尾处。
- }(右大括号)应与{(左大括号)的那一行的开头对齐
- 大括号应该在所有复合语句中使用,即使只有一条语句,当它们是控制结构的一部分时, 比如一个if或者for语句。这样做可以避免以后添加语句时造成的错误。
标示
语句标示是可选的,只有以下语句必须被标示:while, do,for,switch。
return 语句
一条有返回值的return语句不要使用( )(括号)来括住返回值。如果返回表达式,则表达式应与return 关键字在同一行,以避免误加分号错误。
if 语句
if语句应如以下格式:
if (condition){ statements; } if (condition) { statements; } else { statements; } if (condition) { statements; } else if (condition) { statements; } else { statements; }
for 语句
for语句应如以下格式:
for (initialization;condition; update) { statements; } for (variable in object)if (filter) { statements; }
第一种形式的循环用于已经知道相关参数的数组循环。
第二种形式应用于对象中。object原型中的成员将会被包含在迭代器中。通过预先定义hasOwnProperty方法来区分真正的object成员是个不错方法:
for (variablein object) if (object.hasOwnProperty(variable)){ statements; }
while 语句
while语句应如以下格式:
while (condition){ statements; }
do 语句
do语句应如以下格式:
do { statements; } while (condition);
不像别的复合语句,do语句总是以;(分号)结尾。
switch 语句
switch语句应如以下格式:
switch (expression){ case expression: statements; default: statements; }
每个 case与switch对齐。这可避免过分缩进。
每一组statements(除了default应以 break,return,或者throw结尾。不要让它顺次往下执行。
try 语句
try语句应如以下格式:
try { statements; } catch (variable){ statements; } try { statements; } catch (variable){ statements; } finally { statements; }
continue 语句
避免使用continue语句。它很容易使得程序的逻辑过程晦涩难懂。
with 语句
不要使用with语句。
空白
用空行来将逻辑相关的代码块分割开可以提高程序的可读性。
空格应在以下情况时使用:
- • 跟在((左括号)后面的关键字应被一个空格隔开。
while (true) {
- • 函数参数与((左括号)之间不应该有空格。这能帮助区分关键字和函数调用。
- • 所有的二元操作符,除了.(点) 和((左括号)和 [(左方括号)应用空格将其与操作数隔开。
- • 一元操作符与其操作数之间不应有空格,除非操作符是个单词,比如typeof。
- • 每个在控制部分,比如for 语句中的; (分号)后须跟一个空格。
- • 每个,(逗号)后应跟一个空格。
另外的建议
{} 和[]
使用{}代替new Object()。使用[]代替new Array()。
当成员名是一组有序的数字时使用数组来保存数据。当成员名是无规律的字符串或其他时使用对象来保存数据。
,(逗号)操作符
避免使用逗号操作符,除非在特定的for 语句的控制部分。(这不包括那些被用在对象定义,数组定义,var语句,和参数列表中的逗号分隔符。)
作用域
在JavaScript中块没有域。只有函数有域。不要使用块,除非在复合语句中。
赋值表达式
避免在if和while语句的条件部分进行赋值。
if (a = b) {
是一条正确语句?或者
if (a == b) {
才是对的?避免这种不容易判断对错的结构。
===和!==操作符。
使用===和!==操作符会相对好点。==和!=操作符会进行类型强制转换。 特别是, 不要将==用于与错值比较( false,null,undefined,“”,0,NaN)。
令人迷惑的加号和减号
小心在+后紧跟+或++。这种形式很容易仍人迷惑。应插入括号以便于理解。
total = subtotal + +myInput.value;
最好能写成
total = subtotal + (+myInput.value);
这样+ +不会被误认为是++。
eval 是恶魔
eval是JavaScript中最容易被滥用的方法。避免使用它。
eval有别名。不要使用Function构造器。不要给setTimeout或者setInterval传递字符串参数。
(二)
- 变量名称 必须为 小写字母。
- 类的命名使用骆驼命名规则,例如:
Account, EventHandler常量 必须 在对象(类)或者枚举变量的前部声明。枚举变量的命名必须要有实际的意义,并且其成员 必须 使用骆驼命名规则或使用大写:
var NodeTypes = { Element : 1, DOCUMENT: 2 }简写单词 不能使用 大写名称作为变量名:
getInnerHtml(), getXml(), XmlDocument方法的命令 必须 为动词或者是动词短语:
obj.getSomeValue()公有类的命名 必须 使用混合名称(mixedCase)命名。 CSS 变量的命名 必须 使用其对应的相同的公共类变量。 私有类的变量属性成员 必须 使用混合名称(mixedCase)命名,并前面下下划线(_)。例如:
var MyClass = function(){ var _buffer; this.doSomething = function(){ }; }变量如果设置为私有,则前面 必须 添加下划线。
this._somePrivateVariable = statement;通用的变量 必须 使用与其名字一致的类型名称:
setTopic(topic) // 变量 topic 为 Topic 类型的变量所有的变量名 必须 使用英文名称。 变量如有较广的作用域(large scope),必须使用全局变量;此时可以设计成一个类的成员。相对的如作用域较小或为私有变量则使用简洁的单词命名。 如果变量有其隐含的返回值,则避免使用其相似的方法:
getHandler(); // 避免使用 getEventHandler()公有变量必须清楚的表达其自身的属性,避免字义含糊不清,例如:
MouseEventHandler,而非 MseEvtHdlr。请再次注意这条规定,这样做得的好处是非常明显的。它能明确的表达表达式所定义的含义。例如:
dojo.events.mouse.Handler // 而非 dojo.events.mouse.MouseEventHandler类/构造函数 可以使用 扩展其基类的名称命名,这样可以正确、迅速的找到其基类的名称:
EventHandler UIEventHandler MouseEventHandler基类可以在明确描述其属性的前提下,缩减其命名:
MouseEventHandler as opposed to MouseUIEventHandler.
- 术语 "get/set" 不要和一个字段相连,除非它被定义为私有变量。
- 前面加 "is" 的变量名 应该 为布尔值,同理可以为 "has", "can" 或者 "should"。
- 术语 "compute" 作为变量名应为已经计算完成的变量。
- 术语 "find" 作为变量名应为已经查找完成的变量。
- 术语 "initialize" 或者 "init" 作为变量名应为已经实例化(初始化)完成的类或者其他类型的变量。
- UI (用户界面)控制变量应在名称后加控制类型,例如: leftComboBox, TopScrollPane。
- 复数必须有其公共的名称约定(原文:Plural form MUST be used to name collections)。
- 带有 "num" 或者 "count" 开头的变量名约定为数字(对象)。
- 重复变量建议使用 "i", "j", "k" (依次类推)等名称的变量。
- 补充用语必须使用补充词,例如: get/set, add/remove, create/destroy, start/stop, insert/delete, begin/end, etc.
- 能缩写的名称尽量使用缩写。
- 避免产生歧义的布尔变量名称,例如:
isNotError, isNotFound 为非法错误类建议在变量名称后加上 "Exception" 或者 "Error"。 方法如果返回一个类,则应该在名称上说明返回什么;如果是一个过程,则应该说明做了什么。
- 缩进请使用 4 个空白符的制表位。
- 如果您的编辑器支持 文件标签_(file tags),请加添如下的一行使我们的代码更容易阅读:
// vim:ts=4:noet:tw=0:
译注:老外用 VIM 编辑器比较多,此条可以选择遵循。
- 代码折叠必须看起来是完成并且是合乎逻辑的:
var someExpression = Expression1 + Expression2 + Expression3; var o = someObject.get( Expression1, Expression2, Expression3 );注:表达式的缩进与变量声明应为一致的。 注:函数的参数应采用明确的缩进,缩进规则与其他块保持一致。
- 变量必须在声明初始化以后才能使用,即便是 NULL 类型。
- 变量不能产生歧义。
- 相关的变量集应该放在同一代码块中,非相关的变量集不应该放在同一代码块中。
- 变量应该尽量保持最小的生存周期。
- 循环/重复变量的规范:
- 只有循环控制块的话,则必须使用 FOR 循环。
- 循环变量应该在循环开始前就被初始化;如使用 FOR 循环,则使用 FOR 语句初始化循环变量。
- "do ... while" 语句是被允许的。
- "break" 和 "continue" 语句仍然允许使用(但请注意)。
- 条件表达式
- 应该尽量避免复杂的条件表达式,如有必要可以使用临时布尔变量。
- The nominal case SHOULD be put in the "if" part and the exception in the "else" part of an "if" statement.
- 应避免在条件表达式中加入块。
- 杂项
- 尽量避免幻数(Magic numbers),他们应该使用常量来代替。
- 浮点变量必须指明小数点后一位(即使是 0)。
- 浮点变量必须指明实部,即使它们为零(使用 0. 开头)。
- 普通代码段 应该 看起来如下:
while (!isDone){ doSomething(); isDone = moreToDo(); }IF 语句 应该 看起来像这样:
if (someCondition){ statements; } else if (someOtherCondition){ statements; } else { statements; }FOR 语句 应该 看起来像这样:
for (initialization; condition; update){ statements; }WHILE 语句 应该 看起来像这样:
while (!isDone) { doSomething(); isDone = moreToDo(); }DO ... WHILE 语句 应该 看起来像这样:
do { statements; } while (condition);SWITCH 语句 应该 看起来像这样:
switch (condition) { case ABC: statements; // fallthrough case DEF: statements; break; default: statements; break; }TRY ... CATCH 语句 应该 看起来像这样:
try { statements; } catch(ex) { statements; } finally { statements; }单行的 IF - ELSE,WHILE 或者 FOR 语句也 必须 加入括号,不过他们可以这样写:
if (condition){ statement; } while (condition){ statement; } for (intialization; condition; update){ statement; }
- 操作符 建议 使用空格隔开(包括三元操作符)。
- 下面的关键字 避免使用 空白隔开:
- break
- catch
- continue
- do
- else
- finally
- for
- function (如果为匿名函数,例如:var foo = function(){}; )
- if
- return
- switch
- this
- try
- void
- while
- with
- 下面的关键字必须使用空白隔开:
- case
- default
- delete
- function (如果为申明,例如:function foo(){}; )
- in
- instanceof
- new
- throw
- typeof
- var
- 逗号(,) 建议 使用空白隔开。
- 冒号(:) 建议 使用空白隔开。
- 点(.) 在后部 建议 使用空白隔开。
- 点(.) 避免 在前部使用空白。
- 函数调用和方法 避免 使用空白,例如: doSomething(someParameter); // 而非 doSomething (someParameter)
- 逻辑块 之间使用空行。
- 声明 建议 对齐使其更容易阅读。
- 生涩的代码就 没有必要 添加注释了,首先您需要 重写 它们。
- 所有的注释请使用英文。
- 从已解决的方案到未开发的功能,注释 必须 与代码相关。
- 大量的变量申明后 必须 跟随一段注释。
- 注释需要说明的是代码段的用处,尤其是接下来的代码段。
- 注释 没有必要 每行都添加。
下面提供了一些基本的函数或者对象的描述方法:
- 总结(summary): 简短的表述此函数或者对象实现的目的
- 描述(description): 对于此函数或者类的简短的描述
- 返回(return): 描述此函数返回什么(并不包括返回类型)
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! }
没有返回值描述
{ // 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? }
在有的情况下,对于函数的调用和声明是隐义(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. } );
- 简单类型 简单的类型的参数可以直接在函数参数定义中注释说明。
function(/*String*/ foo, /*int*/ bar)...可变类型参数
- ? 可选参数
- ... 说面参数范围不确定
- 数组
function(/*String?*/ foo, /*int...*/ bar, /*String[]*/ baz)...下面是几个修饰符供参考: 全局参数描述 如果你想增加一个描述,你可以将它们移至初始化块。 基本信息格式为: *关键字* 描述字段 ( *key* Descriptive sentence) 参数和变量的格式为: *关键字* ~*类型*~ 描述字段 ( *key* ~*type*~ Descriptive sentence) 注: *关键字* 和 ~*类型*~ 可以使用任何字母和数字表述。
function (foo, bar) { // foo: String // used for being the first parameter // bar: int // used for being the second parameter }
由于实例变量、原型变量和外部变量的声明是一致的,所以有很多的方法声明、修改变量。具体的如何定义和定位应在变量最先出现的位置指明变量的名称、类型、作用域等信息。
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 = "=====";
应使用和对象值和方法一致的标注方式,比如在他们声明的时候:
{ // key: String // A simple value key: "value", // key2: String // Another simple value }
因为函数可以同时返回多个不同(类型)的值,所以应每个返回值之后加入返回类型的注释。注释在行内注释即可,如果所有的返回值为同一类型,则指明返回的类型;如为多个不同的返回值,则标注返回类型为"mixed"。
function() { if (arguments.length) { return "You passed argument(s)"; // String } else { return false; // Boolean } }
有时候您需要在函数或者类中添加对于此函数和类的功能性流程描述。如果您打算这样做,您可以使用 /*======== (= 字符最好出现 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); }