此规范的主要目的是统一组内代码风格,减少组内维护代码成本。此文档大量参考了idiomatic.js, 有觉得不合理的地方,欢迎在issues里面提问题。
##1. 基本的格式化
1-1. 代码缩进采用4个空白符。
1-2. 语句必须都有分号结尾,除了 for, function申明, if, switch, try, while。 非申明式函数也需要分号
var a;
// 错误, 结尾缺少分号
a = function() {
// do some thing.
}
1-3. 所有的循环体和判断体都需要用"{}"括起来。如:
// 正确
if ( condition ) {
doSomething();
}
// 错误
if ( condition ) doSomething();
1-4. 变量声明。同一作用域下的所有变量,全部提至函数顶部,且使用一个var来集中申明。
// 正确
function a() {
var v1 = 1,
v2 = 2,
v3 = 3,
i = 0,
len = 3;
statement;
for ( ; i < len; i++ ) {
// do some thing.
}
}
// 错误
function a() {
var v1 = 1;
var v2 = 2;
var v3 = 3;
statement;
}
// 错误
function a() {
var a = 1;
for ( var i = 0, len = arr.length; i < len; i++ ) {
// do some thing.
}
if ( condition ) {
var b = 2;
// do something.
}
}
// 错误
function a() {
var a = 1;
if ( condition ) {
var b = 2;
// do something.
}
}
同时每个带赋值的变量应当独占一行,第二个起应当在var所需缩进的基础上多一个缩进。需要赋值初始值的优先放在前面,如:
function a() {
var first = 1,
second = 2,
third = 3,
fourth, fifth;
doSomething();
}
单行语句不允许超出80个字符,超出的需要进行合适的断行处理。
1-5-1. 函数链式调用,如果一行太长,链式方法应当在点之前合适的断行,且新行应当在链式开始行所需缩进的基础上多两个缩进, 且一旦断行后后面的每个方法都需要断行。如果某个方法的参数中存在Block,则这个方法在调用之前应当换行。
// 函数链式调用
var $item = $('<div></div>').attr( 'id', 'test' )
.attr( 'id', 'what ever' )
.addClass( 'className' )
.html( 'xxxx' );
// 非赋值语句
$('<div></div>').attr( 'id', 'test' )
.attr( 'id', 'what ever' )
.addClass('className')
.html( 'xxxx' );
// 如果某个方法的参数中带有匿名方法,则这个方法的调用之前应当换行。
var $item = $('<div></div>')
.attr( 'id', function() {
doSomething();
} )
.addClass('className')
.html( 'xxxx' );
// 错误的示例
$('<div></div>').attr( 'id', function() {
doSomething();
} )
.attr( 'id', 'what ever' )
.addClass('className')
.html('xxxx');
1-5-2. 方法参数过长,if语句中条件过多时也需要换行,这种情况下的缩进为2个。同是操作符应当保留在右边结尾处。
callFunc( arg1, arg2, longArgmunent3, longArgmuent4,
longArgmument5 );
function doSomething( arg1, arg2, longArgmunent3, longArgmuent4,
longArgmument5 ) {
doSomething();
}
if ( condition1 && condition2 || condition3 &&
condition5 ) {
doSomething();
}
1-5-3. 每一个块状代码的开始都应当有一个空行。
function myFunc() {
var v1 = 1,
v2 = 2,
v3 = 3;
if ( v1 == 1 ) {
statement
}
while ( condition ) {
statement
}
if ( condition ) {
statement
}
}
var a = {
a: function() {
},
b: function() {
}
}
// 错误
function myFunc() {
var v1 = 1,
v2 = 2,
v3 = 3;
if ( v1 == 1 ) {
statement
}
while ( condition ) {
statement
}
}
1-5-4. if之后的else的代码块应当在前个代码块之后,不允许另起新行。
if ( a === 1 ) {
statement
} else if ( a === 2 ) {
statement
}
// 错误
if ( a === 1 ) {
statement
}
else if ( a === 2 ) {
statement
}
1-5-5. 包含代码块的"{}",应该在"{"后立即换行。
// 正确
for ( t in selected ) {
statement1
statement2
}
for ( t in selected ) {
statement1
}
// 错误
for (t in selected)
{
// statement1
// statement2
}
for (t in selected) { statement }
1-5-6. switch语句中的断行, 每个case之前有一个缩进,case之后的语句两个缩进, 每个break;后都有一个新行,最后一个除外。
switch ( condition ) {
case 'first':
doSomething();
break;
case 'second':
doSomething();
break;
case 'third':
case 'fourth':
doSomething();
break;
default:
break;
}
1-5-7. 超长字符串应该使用"+"进行换行。
// 正确
var myString = 'A rather long string of English text, an error message ' +
'actually that just keeps going and going -- an error ' +
'message to make the Energizer bunny blush (right through ' +
'those Schwarzenegger shades)! Where was I? Oh yes, ' +
'you\'ve got an error and all the extraneous whitespace is ' +
'just gravy. Have a nice day.';
// 错误
var myString = 'A rather long string of English text, an error message \
actually that just keeps going and going -- an error \
message to make the Energizer bunny blush (right through \
those Schwarzenegger shades)! Where was I? Oh yes, \
you\'ve got an error and all the extraneous whitespace is \
just gravy. Have a nice day.';
1-6-1. 包含"()"括号的语句,括号前后应当各有一个空格,括号内部开头和结尾处应当各有一空格,诸如: if / for / while / switch ( statements ) { … } 等;
if ( a === 1 ) {
statement
}
for ( var i = 0; i < 1000; i++ ) {
statement
}
while ( v ) {
statement
}
switch ( v ) {
case '':...
}
// 当括号当做组合来用时,内部不需要空格
if ( !(obj = true) ) {
}
1-6-2. 方法定义和方法调用左括号“(”前面不需要空格, 右括号与{之间始终有一个空格,括号内部开头和结尾应当各有一空格。
// 函数定义
function myFunc( arg ) {
statement
}
// 匿名函数
function( arg ) {
statement
}
// 函数调用
myFunc( arg );
方法调用时,有几种例外,函数调用时有些场景不需要要空格
// 1. 函数调用中无参数
callFunc();
// 2. 参数是obj,array,function直接量时
callFunc([ a, b, c ]);
callFunc({
a: 1,
b: 2
});
// 3. 参数是单独一个字符串时
// 函数接受 `string` 字面量作为参数,没有空格
callFunc('foo');
// 4. 参数是一个立即只是函数时。
callFunc(function() {
doSomething();
});
1-6-3. "="、"=="、"&&"、"||"、">"、"<"前后需要跟空格
1-6-4. 数组成员间的","和各个参数间的","(包括形参和实参)后面需要跟空格。
1-6-5. "[]"中的"["后以及"]"前需要跟空格
for ( t in selected ) {
if ( !hash[ t ] && isOk ) {
deselect( t );
}
}
function MyClass( selector ){
// .....
}
new MyClass('#abc');
var arr = [ 1, 2, 3, 4 ];
// 错误
for (t in selected) {
if (!hash[t]&&isOk){
deselect(t)
}
}
function MyClass(selector){
// .....
}
var arr = [1,2,3,4];
##2. Javascript命名规范 2-1. 构造器采用驼峰式命名,并且首字母大写。如:
function DialogManager ( config ) {
statement;
}
2-2. 枚举类型变量采用驼峰式命名,并且首字母大写。属性名单词全部大写,单词间以下划线分隔。如:
var QueueError = {
QUEUE_LIMIT_EXCEEDED: -100,
FILE_EXCEEDS_SIZE_LIMIT: -110,
ZERO_BYTE_FILE: -120,
INVALID_FILETYPE: -130
};
2-3. 对象的属性或方法名采用小驼峰式(lower camel-case),如"init", "bindEvent", "updatePosition":
Dialog.prototype = {
init: function () {},
bindEvent: function () {},
updatePosition: function () {}
};
2-4. 私有变量名用下划线开头。如:"_current", "_defaultConfig"
function Dialog( config ) {
this._defaultConfig = {};
}
2-5. 常量名全部大写,单词间用下划线分隔。如:“CSS_BTN_CLOSE”, "TXT_LOADING"
function Dialog( config ) {
this.DEFAULT_CONFIG = {
CSS_BTN_CLOSE: 'x-btn-cls',
TXT_LOADING: '加载中...'
};
}
2-6. 方法的返回值如果是布尔值,则必须以is、can、has、should等为前缀
function isGroupId( id ) {
return (id + '').indexOf( 'G' ) > 0;
}
2-7. 简写单词在变量名中出现时也应该遵循驼峰式写法。
// 正确
function getXml () {}
function getId () {}
function getHtml () {}
var xmlDocument;
// 错误
function getXML(){}
function getID(){}
function getHTML(){}
var XMLDocument;
2-8. 在闭包中访问所在实例this指针时,统一使用变量me指向。
var me = this;
setTimeout( function() {
// ...
}, 1000 );
// 错误
var ins = this;
setTimeout( function() {
// ins.
}, 1000 );
2-9. 符合下列场景的变量,请使用对应的命名。
变量名 | 变量含义 | 示例 |
---|---|---|
e | Event对象 |
|
el | HTMLElement |
|
ex | Exception |
|
opts | JSON结构的配置项 |
|
2-10. 所有Zepto/jQuery对象,变量名以$符号开头,如:
var $div = $('<div></div>');
2-11. 变量命名前缀应当是名词,与函数区分开来,函数应当是动词
// 好的写法
var count = 10,
myName = 'Abcd',
found = true;
// 不好的写法
var getCount = 10,
isFound = true;
// 好的写法
function getName() {
return myName;
}
// 不好的写法
function theName(){
return myName;
}
##3. 注释 3-1. Js文档注释,每个js文件顶部都必须包含关于Js文件功能的注释信息。
/**
* @fileoverview 文件功能描述或一些其他相关信息.
*/
3-2. 单行注释。
以两个斜线开始,以行尾结束,两个斜线与内容之间应当有一个空格。
// 这是一个注释
单行注释分以下两种:
- 独占一行,用来解释下一行代码。这行注释之前应当有一个空行,且缩进层级和下一行代码保持一致。
- 在代码行的尾部添加,代码结束到注释之间至少有一个缩进。注释(包括前面的代码部分)不能超过单行最大字符数限制,如果超过改成第一种注释。
function doSomething() {
var a = 3, // 这变量用来存长度
// 这个变量用来存宽度
b,
// 这个变量用来存高度
c;
if ( condition ) {
// 如果代码执行到这,则说明通过安全验证。
popupDialog();
}
}
3-3. 多行注释
当内容比较多用单行注释不能满足需求时,推荐使用多行注释,格式如下,前面应当有个空格。
/*
* 我的注释
* 注释中的第二段
*/
if ( condition ) {
statement
}
3-4. 避免多余的注释,当代码很明了时不应当添加注释。
// 不必要的注释
// 初始化count
var count = 10;
###4. 其他规范 4-1. for-in循环体中必须用hasOwnProperty方法检查成员是否为自身成员。避免来自原型链上的污染。
// 正确
for ( name in object ) {
if ( object.hasOwnProperty( name ) ) {
doSomething();
}
}
4-2. 不要使用with, void, eval。
4-3. 在与类型确定的变量进行条件判断时,使用严格的条件判断符。用===代替==,用!==代替!=。
if ( isValid === true ) {
//
}
4-4. 下面类型的对象不建议用new构造:new Number, new String, new Boolean, new Object(用{}代替), new Array(用[]代替)。
4-5. 引用对象成员用obj.prop代替obj['prop'],除非属性名是变量。
4-6. 使用parseInt将字符串转换成整数时必须使用基数参数。
// 10进制
parseInt( str, 10 );
// 2进制
parseInt( str, 2 );
// 8进制
parseInt( str, 8 );
// 16进制
parseInt( str, 16 );
// 错误
parseInt( str );
另外parseInt( str, 10)
可以考虑是用~~str
或者str>>0
来达到同样的效果
4-7. 函数定义。不要在if、for的代码块中定义函数,在函数中定义内嵌函数时应该把函数定义放在顶部。闭包除外。
// 正确
function outerFunc( va ){
va = va || 0;
function innerFunc(){
//to do....
}
if( va ){
innerFunc();
}
}
// 错误
function outerFunc( va ){
va = va || 0;
if( va ){
function innerFunc(){
//to do....
}
innerFunc();
}
}
4-8. 立即调用的函数用括号括起来.
// 正确
(function(){
doSomething();
})();
// 错误
void function(){
doSomething();
}();
// 错误
(function(){
doSomething();
}());
// 错误
function(){
doSomething();
}();
4-9. 初始化一个可能赋值为对象的变量时,设为null。
var a = null;
// later
a = new Foo();
4-10. 如果某方法,期待返回某一对象时,在异常的情况下应当返回null, 不要返回undefined, 0, false之类的。
function getPerson() {
if ( condition ) {
return new Persion();
} else {
return null;
}
}
4-11. 引号,字符串外层必须使用单引号,内部如果是HTML属性所需的引号则必须为双引号。
var myString = '< a href="http://www.baidu.com">Let\'sGo</a>';
// 错误
var myString = "< a href='http://www.baidu.com'>Let'sGo</a>"';
4-12. 构造函数,使用函数申明定义。
function MyClass( opts ){
statement
}
// 错误
var MyClass = function( opts ){
statement
}
4-13. 不要分发事件对象,目标方法应该明确所需变量。
var myApp = {
handler: function( e ) {
this.showPopup( e.pageX, e.pageY );
},
showPopup: function( x, y ) {
//do popup
}
}
addListener( elem, 'click', function() {
myApp.handler( e );
});
// 错误
var myApp = {
handler: function( e ) {
this.showPopup( e );
},
showPopup: function( e ) {
//do popup
}
}
addListener( elem, "click", function() {
myApp.handler( e );
});