JavaScript Style Rules 代码风格 编码规范
一、命名(Name)
函数命名:functionNamesLikeThis
变量命名:variableNamesLikeThis
类命名:ClassNamesLikeThis
枚举命名:EnumNamesLikeThis
方法命名:methodNamesLikeThis
常量命名:CONSTANT_VALUES_LIKE_THIS
命名空间命名:foo.namespaceNamesLikeThis.bar
文件名命名:filenameslikethis.js
命名——属性和方法(Properties and methods)
1)私有属性、变量和方法(文件中或类中的)应该在命名中加下划线后缀。
2)保护的属性、变量和方法应该没有下划线结尾(类似于公有方法)。
命名——方法和函数参数(Method and function parameter)
1)可选函数参数使用 "opt_" 开头。
2)如果函数的参数的个数是不固定的,那么这个函数应该在末尾包含一个命名为 "var_args" 的参数。你在代码中不一定要使用 "var_args" ,而是使用 arguments 数组。
3)可选函数参数同样可以使用 "@param" 在注释中标注出来。
4)尽管对于一名程序员来说,可能会偏爱其中的一种,但是最好能够同时使用这两种规则。
命名——Getters and Setters
EcmaScript5中对于属性的getters和setters方法尚没有明确的规定。但是就算会有,也应该会遵守其现有的规则。(译者注:目前对多数OOP语言对于getter和setter方法的定义。)
存取方法(Accessor functions)
1 /** 2 * 注意:不应该像下面这么做。 3 */ 4 var foo = { get next() { return this.nextId++; } };
属性的Getters和setters方法并不是必须的。但是如果需要用到,那么getters方法的命名应该是 getFoo() setter方法的命名应该是 setFoo( value ). (如果是布尔值的话,那么getters方法命名为 isFoo()或许更好一些)。
命名空间(Namespaces)
JavaScript并没有内置的包或者命名空间支持。
当你尝试去整合两个项目时,全局命名冲突导致的这个bug可能会造成一个大麻烦。为了使共享JavaScript代码成为可能,我们自己定义这样的规则来避免冲突。
1)为全局代码使用命名空间
总是定义一个与项目或者库相关的唯一的字符串来作为全局范围内的(伪)命名空间。如果你在做一个名为 "Project Sloth" 的项目,一种可能的伪命名空间是:"sloth.*"。
1 var sloth = {}; 2 3 sloth.sleep = function() { 4 ... 5 };
许多的JavaScript类库,包括Closure Library和Dojo toolkit在描述命名空间上都有一个很好的参考。确定一种自己的命名空间规则。
1 goog.provide( 'sloth'); 2 3 sloth.sleep = function() { 4 ... 5 };
2)尊重命名空间的所有权
当你选择一种子命名空间的时候,请确保其父命名空间的所有者知道你这么做了。如果你的一个hats项目以sloth为父命名空间的话,请确保Sloth团队中的你使用了 "sloth.hats" 作为命名空间。
3)为外部和内部的代码使用不同的命名空间
“外部代码”就是并不是来自你的代码库,并且是独立编写的代码。内部代码和外部代码应该被严格的区分。如果你使用的外部代码都是来自 "foo.hats.*" 命名空间下的,那么你内部的代码就不应该再以 "foo.hats.*" 为标志,因为其他的团队定义的新的标志可能会对你的造成影响。
1 foo.require('foo.hats'); 2 3 /** 4 * 注意:不应该这么做。 5 * @constructor 6 * @extends {foo.hats.RoundHat} 7 */ 8 foo.hats.BowlerHat = function() { 9 ... 10 };
如果你需要在外部命名空间上定义新的API,你应该明确的说明公共的API函数。你的内部代码应该以其内部命名规则来命名,以保证一致性和其他的程序员能够优化代码。
1 foo.provide('googleyhats.BowlerHat'); 2 3 foo.require('foo.hats'); 4 5 /** 6 * @constructor 7 * @extends {foo.hats.RoundHat} 8 */ 9 googleyhats.BowlerHat = function() { 10 ... 11 }; 12 13 goog.exportSymbol('foo.hats.BowlerHat', googleyhats.BowlerHat);
4)使用别名来改善过长的名字的可阅读性
对限定的类型使用局部的别名来为其改善可阅读性。局部别名应该匹配整个命名的最后一部分。
1 /** 2 * @constructor 3 */ 4 some.long.namespace.MyClass = function() { 5 ... 6 }; 7 8 /** 9 * @param { some.long.namespace.MyClass} a 10 */ 11 some.long.namespace.MyClass.staticHelper = function(a) { 12 ... 13 }; 14 15 myapp.main = function() { 16 var MyClass = some.long.namespace.MyClass; 17 var staticHelper = some.long.namespace.MyClass.staticHelper; 18 staticHelper( new MyClass() ); 19 };
不要为命名空间创建别名
1 myapp.main = function() { 2 var namespace = some.long.namespace; 3 namespace.MyClass.staticHelper( new namespace.MyClass() ); 4 };
避免使用别名来存取属性,除非是一个枚举。
1 /** @enum {string} **/ 2 some.long.namespace.Fruit = { 3 APPLE: 'a', 4 BANANA: 'b' 5 }; 6 7 myapp.main = function() { 8 var Fruit = some.long.namespace.Fruit; 9 10 switch( fruit ) { 11 case Fruit.APPLE: 12 ... 13 case Fruit.BANANA: 14 ... 15 } 16 }
1 /** 注意:不应该这么做 **/ 2 myapp.main = function() { 3 var MyClass = some.long.namespace.MyClass; 4 MyClass.starticHelper(null); 5 };
绝对不要在全局范围内创建别名,仅仅在函数内部使用。
5)文件名
文件名应该是全部小写的字母以避免在区分大小写的平台上引起冲突。文件名应该以 ".js" 结尾,并且不应该包含除了 "-" 和 "_" 的标点符号。
二、自己定义 "toString()" 方法
必须能够保证自己定义的方法能够执行成功,没有其他的影响。
你通过定义一个自己的 "toString()" 方法来控制对象的字符串返回。这很好,但是你需要保证两点:
1)你的方法必须总能够执行成功。
2)不会有其他的影响。
如果你的方法不能够符合这两个规则,那么回很容易就出现问题。例如,如果你的 "toString()" 方法要做一个调用,而那个调用是需要输出对象的名字,毫无疑问这个调用肯定会失败,因为它会去调用 "toString()"。
三、延迟初始化
并不总是需要在定义的地方进行初始化,所以延迟初始化是个好主意。
四、准确的范围
总是使用明确的范围,这样可以增加代码的清晰度。例如,不要在范围内使用 "window" ,因为你可能在其他的应用程序中使用的你的函数,"window" 可能不再是内容中的"window"。
五、代码格式
1)大括号
1 if( something ){ 2 //... 3 } else { 4 //... 5 }
2)数组和对象的初始化
单行的数组或对象的初始化也是被允许的
1 var arr = [1, 2, 3]; // 在声明的前后没有空格 [ or before ]. 2 var obj = {a: 1, b: 2, c: 3}; // 在声明的前后没有空格 { or before }
多行的数组初始化和对象初始化使用空格缩进,就像一个区块。
1 // 对象初始化 2 var inset = { 3 top: 10, 4 right: 20, 5 bottom: 15, 6 left: 10 7 }; 8 9 //数组初始化 10 this.rows_ = [ 11 '"Slartibartfast" <fjordmaster@magrathea.com>', 12 '"Zaphod Beeblebrox" <theprez@universe.gov>', 13 '"Ford Prefect" <ford@theguide.com>', 14 '"Arthur Dent" <has.no.tea@gmail.com>', 15 '"Marvin the Paranoid Android" <marv@googlemail.com>', 16 'the.mice@magrathea.com' 17 ]; 18 19 // 在一个方法中使用 20 goog.dom.createDom( goog.dom.TagName.DIV, { 21 id: 'foo', 22 className: 'some-css-class', 23 style: 'display:none' 24 }, 'Hello, world!');
过长的定义或值会在将定义排列对齐时造成问题,因此不使用排列对齐。
1 CORRECT_Object.prototype = { 2 a: 0, 3 b: 1, 4 lengthyName: 2 5 }; 6 7 //不要像下面这么做 8 WRONG_Object.prototype = { 9 a : 0, 10 b : 1, 11 lengthyName : 2 12 };
3)函数参数
如果可能的话,函数所有的参数都应该被放在一行内。但是如果这样做会一行会超过80个字符,那么参数应该换行。为了保持间距,你应该在80个字符左右换行,或者把每个参数放在单独的一行来增加可读性。这个缩进可以用四个空格,或者是和开始的第一个参数对齐。
1 // Four-space, wrap at 80. Works with very long function names, survives 2 // renaming without reindenting, low on space. 3 goog.foo.bar.doThingThatIsVeryDifficultToExplain = function( 4 veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, 5 tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) { 6 // ... 7 }; 8 9 // Four-space, one argument per line. Works with long function names, 10 // survives renaming, and emphasizes each argument. 11 goog.foo.bar.doThingThatIsVeryDifficultToExplain = function( 12 veryDescriptiveArgumentNumberOne, 13 veryDescriptiveArgumentTwo, 14 tableModelEventHandlerProxy, 15 artichokeDescriptorAdapterIterator) { 16 // ... 17 }; 18 19 // Parenthesis-aligned indentation, wrap at 80. Visually groups arguments, 20 // low on space. 21 function foo(veryDescriptiveArgumentNumberOne, veryDescriptiveArgumentTwo, 22 tableModelEventHandlerProxy, artichokeDescriptorAdapterIterator) { 23 // ... 24 } 25 26 // Parenthesis-aligned, one argument per line. Visually groups and 27 // emphasizes each individual argument. 28 function bar(veryDescriptiveArgumentNumberOne, 29 veryDescriptiveArgumentTwo, 30 tableModelEventHandlerProxy, 31 artichokeDescriptorAdapterIterator) { 32 // ... 33 }
4)匿名函数
当在一个函数的参数中定义一个匿名函数时,匿名函数体以外层语句边界缩进两个空格,或者是以"function"关键字为边界缩进两个空格。这使得匿名函数的函数体更容易阅读。
1 prefix.something.reallyLongFunctionName('whatever', function(a1, a2) { 2 if (a1.equals(a2)) { 3 someOtherLongFunctionName(a1); 4 } else { 5 andNowForSomethingCompletelyDifferent(a2.parrot); 6 } 7 }); 8 9 var names = prefix.something.myExcellentMapFunction( 10 verboselyNamedCollectionOfItems, 11 function(item) { 12 return item.name; 13 });
5)更多的缩进
事实上,除了数组、对象缩进和匿名函数缩进以外,其他所有的表达式都应该在换行的时候缩进,缩进四个空格而不是两个。
1 someWonderfulHtml = '' + 2 getEvenMoreHtml(someReallyInterestingValues, moreValues, 3 evenMoreParams, 'a duck', true, 72, 4 slightlyMoreMonkeys(0xfff)) + 5 ''; 6 7 thisIsAVeryLongVariableName = 8 hereIsAnEvenLongerOtherFunctionNameThatWillNotFitOnPrevLine(); 9 10 thisIsAVeryLongVariableName = 'expressionPartOne' + someMethodThatIsLong() + 11 thisIsAnEvenLongerOtherFunctionNameThatCannotBeIndentedMore(); 12 13 someValue = this.foo( 14 shortArg, 15 'Some really long string arg - this is a pretty common case, actually.', 16 shorty2, 17 this.bar()); 18 19 if (searchableCollection(allYourStuff).contains(theStuffYouWant) && 20 !ambientNotification.isActive() && (client.isAmbientSupported() || 21 client.alwaysTryAmbientAnyways())) { 22 ambientNotification.activate(); 23 }
6)空行
使用空行来组织相关的代码块。
1 doSomethingTo(x); 2 doSomethingElseTo(x); 3 andThen(x); 4 5 nowDoSomethingWith(y); 6 7 andNowWith(z);
7)二元和三元运算符
总是将这些操作放在新的一行的开始,这样你就无需去考虑如何正确的断句了。另外空行和缩进参考上述规则。
1 var x = a ? b : c; // All on one line if it will fit. 2 3 // Indentation +4 is OK. 4 var y = a ? 5 longButSimpleOperandB : longButSimpleOperandC; 6 7 // Indenting to the line position of the first operand is also OK. 8 var z = a ? 9 moreComplicatedB : 10 moreComplicatedC;
下面是包含 "." 操作符的
1 var x = foo.bar(). 2 doSomething(). 3 doSomethingElse();
8)圆括号
只有在语法语句需要的地方使用。
不要对一元运算符使用圆括号例如 "delete, typeof" 和 "void" 以及其他关键字,例如 "return, throw, case, in, new"。
六、字符串
使用单引号代替双引号。
使用单引号来代替双引号会更好。特别是当创建一个HTML字符串时。
var msg = 'This is some HTML';
七、能见度(私有和保护的字段)
待定。。。
原文地址:http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
暂时这么多,还有的以后会补全。
欢迎纠错(我的英语很一般),翻译这个够呛。
Email: quanshiai324@gmail.com