本文定义了个人的JavaScript编码规范。
每一行代码严格以80字符为最大长度,即一行包括前后的空格,不得超过80个字符。
由于必定存在一些特殊的原因,导致一条语句的长度超过80,应当按以下原则进行切分:
按一定长度截断字符串,并使用+
运算符进行连接。分隔字符串尽量按语音进行,如不要在一个完整的名词中间断开。
特别的,对于HTML片段的拼接,通过缩进,保持和HTML相同的结构:
var html = '' // 此处用一个空字符串,以便整个HTML片段都在新行严格对齐
+ '<article>'
+ '<h1>Title here</h1>'
+ '<p>This is a paragraph</p>'
+ '<footer>Complete</footer>'
+ '</article>';
也可使用数组来进行拼接,相对+
运算更容易调整缩进:
var html = [
'<article>',
'<h1>Title here</h1>',
'<p>This is a paragraph</p>',
'<footer>Complete</footer>',
'</article>';
];
html = html.join(''); // 注意需要join
当参数过多,在一行书写函数调用语句会超过80个字符的限制时,应当将每个参数独立写在一行上,并将结束的右括号)
独立一行,所有参数增加一个缩进,以控制每行的长度,如:
// 注意每一个参数的缩进
foo(
aVeryVeryLongArgument,
anotherVeryLongArgument,
callback
);
当参数较多,一行一个书写会导致过长时,应当按逻辑对参数进行组合,最经典的是jQuery.format
函数,如:
// 将参数分为“模板”和“数据”两块
jQuery.format(
dateFormatTemplate,
year, month, date, hour, minute, second
);
// 将参数分为“模板”、“日期”和“时间”
jQuery.format(
dateFormatTemplate,
year, month, date,
hour, minute, second
);
三元运算符由3部分组成,因此其换行应当根据每个部分的长度不同,形成3种不同的情况:
// 无需换行
var result = condition ? resultA : resultB;
// 条件超长的情况
var result = thisIsAVeryVeryLongCondition ?
resultA : resultB;
// 结果分支超长的情况
var result = condition ?
thisIsAVeryVeryLongResult :
resultB;
var result = condition ?
resultA :
thisIsAVeryVeryLongResult;
不得出现以下情况:
// 最后一个结果很长,但不建议合并条件和第一分支
// 不要这么干
var result = condition ? resultA :
thisIsAVeryVeryLongResult;
这种方法会导致语义上的分裂,即条件和分支在一行,另一分支在一行,没有按逻辑进行组织。
当因为较复杂的逻辑条件组合导致80个字符无法满足需求时,考虑将每个条件独立一行,逻辑运算符放置在行尾或行首进行分隔,或将部分逻辑按逻辑组合进行分隔,最终将右括号)
与左大括号{
放在独立一行,如:
// 注意逻辑运算符前的缩进
if (user.isAuthenticated()
&& user.isInRole('admin')
&& user.hasAuthority('add-admin')
|| user.hasAuthority('delete-admin')
) {
// Code
}
在特定的位置加上空格有助于代码的可读性,以下位置必须加上空格:
+
, -
等等{
前,包括if
、else
、try
、finally
这些关键字之后,以及函数定义的参数列表之后for
、switch
、while
{ ... }
)的每个属性名的冒号:
后,
后{ ... }
)左大括号{
后和右大括号}
前注意,在函数参数列表之前不得加上空格,以下是一个函数的正确声明方式:
function foo(x, y, z) {
// FunctionBody
}
var foo = function(x, y, z) {
// FunctionBody
}
严格采用4个空格为一次缩进,不得采用TAB作为缩进。在以下情况下必须缩进:
switch
下的case
和default
必须缩进缩进会带来自然的对齐,在缩进之外,不需要额外的对齐:
=
符号:
符号在以下位置必须换行:
if
、else
、catch
、finally
、while
等关键字前对于因为单行长度超过限制时产生的换行,参考行长度中的策略进行分隔。
除此之外,存在额外的策略:
如果对象属性较多导致每个属性一行占用空间过大,可以按语义或逻辑进行分组的组织,如:
// 英文-数字的映射
var mapping = {
one: 1, two: 2, three: 3, four: 4, five: 5,
six: 6, seven: 7, eight: 8, nine: 9, ten: 10,
eleven: 11, twelve: 12, thirteen: 13, fourteen: 14, fifteen: 15,
sixteen: 16, seventeen: 17, eighteen: 18, nineteen: 19, twenty: 20
};
通过5个一组的分组,将每一行控制在合理的范围内,并且按逻辑进行了切分。
对于项目较多的数组,也可以采用相同的方法,如:
// 数字-英文的映射
var mapping = [
'one', 'two', 'three', 'four', 'five',
'six', 'seven', 'eight', 'nine', 'ten',
'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen',
'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty'
];
当函数调用时,传递的参数大于或等于2个,且有一个或以上参数跨越多行时,要求每一个参数独立一行,这通常出现在匿名函数或者对象初始化等作为参数时,如setTimeout
函数等:
setTimeout(
function() {
alert('hello');
},
200
);
order.data.read(
'id=' + me.model.id,
function(data) {
me.attchToModel(data.result);
callback();
},
300
);
如果认为每个参数单独一行占用过多的空间,则应当将跨域多行的参数独立出来为一个变量:
function attachDataToModel() {
me.attchToModel(data.result);
callback();
}
order.data.read('id=' + me.model.id, attachDataToModel, 300);
严格按照每个对象的起始{
和结束}
在独立一行的风格书写,如:
var array = [
{
// ...
},
{
// ...
}
];
在代码规范中最容易被人忽略的就是空行。一般来说,代码应该看起来就像一篇如行云流水般的文章, 而不是一篇用连续的用文字堆砌起来的文本。空行就是用来区分相关行和非相关行代码的。
在以下位置必须添加空行:
if
、else
、catch
、finally
、while
等关键字前命名的方法通常有以下几类:
thisIsAnApple
ThisIsAnApple
this_is_an_apple
this-is-an-apple
根据不同类型的内容,采用不同的命名法:
_
开头IS_DEBUG_ENABLED
命名同时还需要关注语义,如:
一个var
关键字必须只声明一个变量。
变量必须即用即声明,不得在函数(或其它形式的代码块)起始位置统一声明所有变量。
字符串必须使用单引号'
。
对象和数组优先使用其初始化器({ ... }
和[ ... ]
)声明,不要使用new Object
和new Array
。
如果一个对象的所有属性名均不是保留字,则该对象声明时,所有属性名不得添加引号,这包括属性名是数字的情况。
如果一个对象的属性名有一个或多个是保留字,则该对象声明时,所有属性名必须添加引号。
允许使用异常,但在创建Error
对象时,必须明确地传递message
参数。
采用jQuery.inherit
或相似机制实现继承,不得随意覆盖prototype
属性。
声明类的方法时,采用MyClass.prototype.foo = function() {}
的形式,不得直接覆盖prototype
属性。
需要修改内置对象的原型时,该代码必须由一个高级别工程师进行Review。
eval
和with
当代码中使用eval
或with
时,该代码必须由一个同级别工程师和一个高级别工程师进行Review。