本文档的目标是使javascript代码风格保持一致,容易被理解和被维护。
虽然本文档是针对javascript设计的,但是在使用各种javascript的预编译器(如coffescript等) 时,适用的部分也应尽量遵循本文档的约定。
解释:
UTF-8 编码具有更广泛的适应性。BOM 在使用程序或工具处理文件时可能造成不必要的干扰。
示例:
// good
switch (variable) {
case '1':
// do...
break;
case '2':
// do...
break;
default:
// do...
}
// bad
switch (variable) {
case '1':
// do...
break;
case '2':
// do...
break;
default:
// do...
}$('#items')
.find('.selected')
.highlight()
.end();解释:超长的不可分割的代码允许例外,比如复杂的正则表达式。长字符串不在例外之列。
示例:
// 仅为按逻辑换行的示例,不代表setStyle的最优实现
function setStyle(element, property, value) {
if (element == null) {
return;
}
element.style[property] = value;
}解释:特别的,对于 if...else...、try...catch...finally 等语句,在 }
之后不换行,而是添加一个空格。
示例:
function funcName() {
// some statements;
}
if (...) {
// some statements;
}
if (condition) {
// some statements;
} else {
// some statements;
}
try {
// some statements;
} catch (ex) {
// some statements;
}示例:
// good
if (user.isAuthenticated()
&& user.isInRole('admin')
&& user.hasAuthority('add-admin')
|| user.hasAuthority('delete-admin')
) {
// Code
}
var result = number1 + number2 + number3
+ number4 + number5;
// bad
if (user.isAuthenticated() &&
user.isInRole('admin') &&
user.hasAuthority('add-admin') ||
user.hasAuthority('delete-admin')) {
// Code
}
var result = number1 + number2 + number3 +
number4 + number5;示例:
// good
var obj = {
a: 1,
b: 2,
c: 3
};
foo(
aVeryVeryLongArgument,
anotherVeryLongArgument,
callback
);
// bad
var obj = {
a: 1
, b: 2
, c: 3
};
foo(
aVeryVeryLongArgument
, anotherVeryLongArgument
, callback
);示例
var html = '' // 此处用一个空字符串,以便整个HTML片段都在新行严格对齐
+ '<article>'
+ '<h1>Title here</h1>'
+ '<p>This is a paragraph</p>'
+ '<footer>Complete</footer>'
+ '</article>';示例:
var a = !arr.length;
a++;
a = b + c;示例:
// good
if (condition) {
}
while (condition) {
}
function funcName() {
}
// bad
if (condition){
}
while (condition){
}
function funcName(){
}示例:
// good
if (condition) {
}
while (condition) {
}
(function () {
})();
// bad
if(condition) {
}
while(condition) {
}
(function() {
})();示例:
// good
var obj = {
a: 1,
b: 2,
c: 3
};
// bad
var obj = {
a : 1,
b:2,
c :3
};示例:
// good
function funcName() {
}
funcName();
// bad
function funcName () {
}
funcName ();示例:
// good
var funcName = function () {
};
var value = (function () {
}());
// bad
var funcName = function() {
};
var value = (function() {
}());示例:
// good
callFunc(a, b);
// bad
callFunc(a , b) ;
callFunc(a,b);示例:
// good
callFunc(param1, param2, param3);
save(this.list[this.indexes[i]]);
needIncream && (variable += increament);
if (num > list.length) {
}
while (len--) {
}
// bad
callFunc( param1, param2, param3 );
save( this.list[ this.indexes[ i ] ] );
needIncreament && ( variable += increament );
if ( num > list.length ) {
}
while ( len-- ) {
}解释:
声明包含元素的数组与对象,只有当内部元素的形式较为简单时,才允许写在一行。元素复杂的情况,还是应该换行书写。
示例:
// good
var arr1 = [];
var arr2 = [1, 2, 3];
var obj1 = {};
var obj2 = {name: 'obj'};
var obj3 = {
name: 'obj',
age: 20,
sex: 1
};
// bad
var arr1 = [ ];
var arr2 = [ 1, 2, 3 ];
var obj1 = { };
var obj2 = { name: 'obj' };
var obj3 = {name: 'obj', age: 20, sex: 1};示例:
var value_name_like_this;function funcNameLikeThis(){
//code....
}示例:
var CONSTANT_NAME_LIKE_THIS;示例:
function funcName(param_name_like_this) {
//code....
}示例:
function ClassNameLikeThis(){
//code....
}示例:
function ClassNameLikeThis(){
this.valueNameLikeThis = value;
this.functionInClass = function () {
//code....
}
}示例:
var TargetState = {
READING: 1,
READED: 2,
APPLIED: 3,
READY: 4
};示例:
var nameSpace = {};示例:
function XMLParser() {
}
function insertHTML(element, html) {
}
var httpRequest = new HTTPRequest();示例:
function Engine(options) {
}示例:
function getStyle(element) {
}示例:
var isReady = false;
var hasMoreCommands = false;示例:
var loadingData = ajax.get('url');
loadingData.then(callback);解释:
不通过 var 定义变量将导致变量污染全局环境。
示例:
// good
var name = 'MyName';
// bad
name = 'MyName';示例:
// good
var hangModules = [];
var missModules = [];
var visited = {};
var number_one = 1,
number_two = 2;
// bad
var hangModules = [], missModules = [], visited = {}, number_one = 1, number_two = 2;解释:在顶部统一声明变量有助于增强可读性,即使放到中间,js解析器也会提升至顶部(hosting)
示例:
// good
function kv2List(source) {
var list = [];
var key;
var item;
for (key in source) {
if (source.hasOwnProperty(key)) {
item = {
k: key,
v: source[key]
};
list.push(item);
}
}
return list;
}
// bad
function kv2List(source) {
var list = [];
for (var key in source) {
if (source.hasOwnProperty(key)) {
var item = {
k: key,
v: source[key]
};
list.push(item);
}
}
return list;
}解释:
使用 === 可以避免等于判断中隐式的类型转换。
示例:
// good
if (age === 30) {
// ......
}
// bad
if (age == 30) {
// ......
}示例:
// 字符串为空
// good
if (!name) {
// ......
}
// bad
if (name === '') {
// ......
}
// 字符串非空
// good
if (name) {
// ......
}
// bad
if (name !== '') {
// ......
}
// 数组非空
// good
if (collection.length) {
// ......
}
// bad
if (collection.length > 0) {
// ......
}
// 布尔不成立
// good
if (!notTrue) {
// ......
}
// bad
if (notTrue === false) {
// ......
}
// null 或 undefined
// good
if (noValue == null) {
// ......
}
// bad
if (noValue === null || typeof noValue === 'undefined') {
// ......
}解释:
循环体中的函数表达式,运行过程中会生成循环次数个函数对象。
示例:
// good
function clicker() {
// ......
}
for (var i = 0, len = elements.length; i < len; i++) {
var element = elements[i];
addListener(element, 'click', clicker);
}
// bad
for (var i = 0, len = elements.length; i < len; i++) {
var element = elements[i];
addListener(element, 'click', function () {});
}示例:
// good
var width = wrap.offsetWidth + 'px';
for (var i = 0, len = elements.length; i < len; i++) {
var element = elements[i];
element.style.width = width;
// ......
}
// bad
for (var i = 0, len = elements.length; i < len; i++) {
var element = elements[i];
element.style.width = wrap.offsetWidth + 'px';
// ......
}示例:
// good
num + '';
// bad
new String(num);
num.toString();
String(num);示例:
// good
+str;
// bad
Number(str);[建议] 转换成boolean时,使用!!。
示例:
var num = 3.14;
!!num;示例:
// good
var obj = {};
// bad
var obj = new Object();解释:
属性名符合 Identifier 的要求,就可以通过 . 来访问,否则就只能通过 [expr] 方式访问。
通常在 JavaScript 中声明的对象,属性命名是使用 Camel 命名法,用 . 来访问更清晰简洁。部分特殊的属性(比如来自后端的JSON),可能采用不寻常的命名方式,可以通过 [expr] 方式访问。
示例:
info.age;
info['more-info'];示例:
// good
var info = {
'name': 'someone',
'age': 28,
'more-info': '...'
};
// bad
var info = {
name: 'someone',
age: 28,
'more-info': '...'
};[强制] 使用数组字面量[]创建新数组,除非想要创建的是指定长度的数组。
示例:
// good
var arr = [];
// bad
var arr = new Array();解释:
数组对象可能存在数字以外的属性, 这种情况下 for in 不会得到正确结果.
示例:
var arr = ['a', 'b', 'c'];
arr.other = 'other things'; // 这里仅作演示, 实际中应使用Object类型
// 正确的遍历方式
for (var i = 0, len = arr.length; i < len; i++) {
console.log(i);
}
// 错误的遍历方式
for (i in arr) {
console.log(i);
}解释:
将过多的逻辑单元混在一个大函数中,易导致难以维护。一个清晰易懂的函数应该完成单一的逻辑单元。复杂的操作应进一步抽取,通过函数的调用来体现流程。
特定算法等不可分割的逻辑允许例外。
示例:
function syncViewStateOnUserAction() {
if (x.checked) {
y.checked = true;
z.value = '';
}
else {
y.checked = false;
}
if (!a.value) {
warning.innerText = 'Please enter it';
submitButton.disabled = true;
}
else {
warning.innerText = '';
submitButton.disabled = false;
}
}
// 直接阅读该函数会难以明确其主线逻辑,因此下方是一种更合理的表达方式:
function syncViewStateOnUserAction() {
syncXStateToView();
checkAAvailability();
}
function syncXStateToView() {
if (x.checked) {
y.checked = true;
z.value = '';
}
else {
y.checked = false;
}
}
function checkAAvailability() {
if (!a.value) {
displayWarningForAMissing();
}
else {
clearWarnignForA();
}
}示例:
function TextNode(value, engine) {
this.value = value;
this.engine = engine;
}
TextNode.prototype.clone = function () {
return this;
};[建议] 对于多个元素的集合,尽可能使用context.getElementsByTagName获取。其中context可以为 document或其他元素。指定tagName参数为 * 可以获得所有子元素。
解释:
DOM操作是非常耗时的一种操作,减少DOM操作有助于提高性能。举一个简单的例子,构建一个列表。我们可以用两种方式:
-
在循环体中 createElement 并 append 到父元素中。
-
在循环体中拼接 HTML 字符串,循环结束后写父元素的 innerHTML。
第一种方法看起来比较标准,但是每次循环都会对 DOM 进行操作,性能极低。在这里推荐使用第二种方法。