本文译自Javascript大师Douglas Crockford的文章(2016.10.27版),以飨英文不太好的同学。如果英文过关,建议读原文
原文 Code Conventions for the JavaScript Programming Language
排版规则
粗体:Javascript关键词、操作符等
斜体:译者补充说明
部分代码块为译者所加,前面注有:// 译者加
译文全文
本文是Javascript编程过程中用到的一系列约定和规则。
对于一个组织来说,从长远来看,软件的价值与其代码的质量成正比例。在一个程序的整个生命中,会经历很多双眼、很多双手。如果一个程序能清晰的传达其结构和特性,那么未来修改时,这些结构和特性被破坏的可能性会较小。代码约定就是为了降低程序的脆弱性(brittleness)。
JavaScript代码都是要公开发布的,所以它总是需要具有发布质量。简洁是有价值的。
JavaScript文件
应该保存为 .js 文件。
JavaScript代码不应该嵌入到HTML文件中,除非此代码仅为这一个HTML文件所用(译的欠妥)。将JavaScript嵌入到HTML会增大文件,导致无法通过缓存、压缩等机制减小文件。
空白(Whitespace)
下面这些规则一直以来都是文字书写的好习惯。除非有明显的好处,否则不应该被打破。
空行(blank line),将逻辑上有关联的代码放在一块,可以提高可读性。
空格(blank space),在以下情况中都应该使用:
- 一个关键词后跟一个 ( 时,应该用一个空格隔开。应用空格,可以使不是调用的地方看起来不像调用(Spaces are used to make things that are not invocations look less like invocations.)。如下例,if 或 while 之后应该有空格:
while (true) {
- 在function和调用( ( )之间不应该有空格。这样可以将关键词和函数调用区分开来。
// 译者加
some_func(a, b);
- 关键词 function 后面总是要跟空格
// 译者加
function foo() { ...
var bar = function () { ...
- 一元操作符和其操作数之间不应该有空格,除非操作符是一个单词,比如 typeof
// 译者加
some_var++;
++some_var;
- 二元操作符和其操作数之间总是用一个空格隔开,这几个例外:. ( [
// 译者加
var c = a + b;
- 逗号 , 之后总是跟空格或换行
- 用于语句结束的分号 ; 后总是需要换行
- for 语句中的分号 ; 后总是跟一个空格
// 译者加
for (var i = 0; i < 5; i++) {
每一个语句都应该跟当前缩进对齐,最外层缩进对齐编辑区左侧。当上一行的最后一个标识为 { [ ( 时,本行缩进4个空格;相应的关闭标识 } ] ) 应新起一行,缩进减4个空格
// 译者加
function foo() {
while (true) {
console.log('hello');
}
}
三元操作符看起来比较晕,所以,? 总是新起一行并缩进4个空格,: 也总是新起一行,与 ? 对齐。条件判断需用 ( ) 包起来:
var integer = function (
value,
default_value
) {
value = resolve(value);
return (typeof value === "number")
? Math.floor(value)
: (typeof value === "string")
? value.charCodeAt(0)
: default_value;
};
如果 . 是一行的第一个字符,缩进4个空格。
应避免一行过于长。如果一个语句在一行放不下,那就有必要将它分开。最好在 { [ ( , 之后换行,或者 . ? : 之前换行。如果在这地方换行不合适,那就在操作符之后换行,新行缩进8个空格。但是这8个空格不改变当前缩进。
块(case catch default else finally)不是语句,故不需要缩进。
Tab(制表符)和空格不应该混用。二者只选其一,以避免两者都用带来的问题。个人偏好设置并不可靠。Tab或空格并不比对方更具优势。50年前,Tab的优势在于节省内存,但摩尔定律已经否定了这一优势(此处不是很懂)。空格比Tab有一个明确的优势:目前还没有一个可依赖的标准规定一个Tab占几个空格,但毫无争议的是,一个空格确切的占一个空格。所以,总是使用空格。如果必须,你可以在编辑时使用Tab,但确保在提交(commit)时转为空格。或许有一天我们将最终有一个关于Tab的统一标准,不过在那天到来之前,使用空格,是明智的选择。
注释(Comment)
应该不吝啬注释。留下一些信息,有助于未来的人(包括你自己)理解你做了什么、为什么要做。注释应该好好写、写清楚,要像写代码一样写注释。一些小幽默也是鼓励的,不过困难和抱怨就不要写了。
有一点很重要:注释应该保持“新鲜”(up-to-date)。错误的注释反而会使程序更难读、更难懂。
注释应该有意义,着重说明不能从代码里一眼就看出来的隐含意义。但也不要浪费时间写下面这样的注释:
i = 0; // 把i设为0
变量声明(Variable Declarations)
所有的变量都应该在使用之前声明。JavaScript并不强制如此,但这样做可以使程序更易读,并且容易发现未声明的变量可能是隐式的(这句译的欠妥)。隐式的全局变量应该杜绝。尽量少用全局变量。
推荐:变量的声明语句后跟注释。如果可能,以字母顺序排列:
var currentEntry; // currently selected table entry
var level; // indentation level
var size; // size of table
JavaScript中的var没有作用域,故,将变量声明在块(block)中会给有C语言经历的同学造成迷惑。
函数声明(Function Declaration)
所有的function都应该先声明后使用。内部函数(inner function)应跟在var后面(即先声明变量,再声明内部函数),这样可以清楚知道当前作用域(scope)有哪些变量。
函数名和 ( 之间不应该有空格;) 和 { 之间应该有一个空格。函数体缩进4个空格,} 应和函数声明的那一行开始对齐。
function outer(c, d) {
var e = c * d;
var x; // no use
function inner(a, b) {
return (e * a) + b;
}
return inner(0, 1);
}
这样的约定很适合JavaScript,因为在Javascript中函数和object定义(object literal)可以在任何可以放表达式的地方。可以最大程度的提高内部函数和复杂结构的可读性。
function getElementsByClassName(className) {
var results = [];
walkTheDOM(document.body, function (node) {
var array; // array of class names
var ncn = node.className; // the node's classname
// 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 list of results.
if (ncn && ncn.split(" ").indexOf(className) >= 0) {
results.push(node);
}
});
return results;
}
如果是匿名函数,在关键词 function 和 ( 之间应该有一个空格。如果没有,看起来好像这个函数的名字是function,这当然是错误的解读。
div.onclick = function (e) {
return false;
};
that = {
method: function () {
return this.datum;
},
datum: 0
};
应尽量少用全局函数
如果一个函数被即刻调用(to be invoked immediately),那么整个调用表达式应用 ( ) 包起来,以清楚地表达:产生的值是函数执行的结果,而非函数本身
var collection = (function () {
var keys = [];
var values = [];
return {
get: function (key) {
var at = keys.indexOf(key);
if (at >= 0) {
return values[at];
}
},
set: function (key, value) {
var at = keys.indexOf(key);
if (at < 0) {
at = keys.length;
}
keys[at] = key;
values[at] = value;
},
remove: function (key) {
var at = keys.indexOf(key);
if (at >= 0) {
keys.splice(at, 1);
values.splice(at, 1);
}
}
};
}());
命名(Names)
名字应该由26个字母的大小写(A...Z, a...z),10个数字(0...9),以及下划线:_ 组合而成。避免使用国际字符,因为他们可能被误读。不要使用 $ 和 \
不要将 _ 用于名字首字母。这样做有时是为了表示“私有”(privacy),但并不能真正的提供私有(保护)。如果私有很重要,应使用闭包(closure)。避免使用这种名不副实的做法。
绝大多数变量名和function名应该以小写字母开头。
必须用 new 调用的构造函数(constructor function),名字应该以大写字母开头。如果 new 缺失,JavaScript并不视为一个编译时(compile-time)错误,也不视为一个运行时(run-time)错误,但却可能有非预期的结果。首字母大写是我们唯一的保护机制。
全局变量应该全部用大写字母组成。
语句(Statements)
简单语句(Simple Statements)
一行应最多包含一个语句。每一个简单语句都应以 ; 结束。注意:函数定义(function literal)或对象定义(object literal)的赋值语句(assignment statement)也是赋值语句,故也应以 ; 结束。
// 译者加
var foo = {
name: 'x'
};
var bar = function () {
return 'bar';
};
JavaScript允许任何表达式(expression)作为语句(statement)使用。这会掩盖一些错误,有 ; 时更甚。可以作为语句的表达式仅建议:赋值、调用、delete
复合语句(Compound Statements)
复合语句:由 { } 包起来的一系列语句
- 包起来的语句应缩进4个空格
- { 应该在复合语句开始的那一行行尾
- } 应该新起一行,并与相应的 { 所在行行首对齐
- { } 应包起所有的语句,即使只有一条语句(当它作为控制结构(control structure)的一部分时,比如 if for),这样可以避免后续添加语句时引入错误。
// 译者加
if (true) {
console.log('true');
// do_some_th
} else {
console.log('false');
}
标签(Labels)
应避免使用语句标签。只有下面语句才可应用:while do for switch
return语句
返回的值表达式(value expression)必须与 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
}
while语句
while 语句应该有如下形式:
while (condition) {
statements
}
do语句
do 语句应该有如下形式:
do {
statements
} while (condition);
跟其他复合语句不同的是:do 语句总是以 ; 结束
switch语句
switch 语句应该有如下形式:
switch (expression) {
case expression:
statements
default:
statements
}
case 与 switch 对齐,以避免缩进太多。因 case 不是语句,故不需要“像”语句。
每一组statements(default除外)都应该以 break / return / throw 结束。不应穿透(fall through)
continue语句
避免使用该语句。因它会使控制流(control flow)不清晰。
with语句
{ } 和 [ ]
使用 { } ,而不用 new Object()。
使用 [ ] ,而不用 new Array()。
当成员的名字是整数序列时,使用数组(array)。
当成员的名字是无序字符串或名字时,使用对象(object)。
逗号操作符(, Operator)
不应使用逗号操作符。(并不是指我们广泛使用的逗号分隔符)
赋值表达式(Assignment Expressions)
避免在 if while 语句的条件判断中进行赋值操作 ,下面这句:
if (a = b) {
是正确的吗?还是下面这句:
if (a == b) {
才是本意?所以,应避免这种容易引起歧义的写法
=== and !== 操作符
请使用 === 和 !== 操作符。== 和 != 有强制转换,应避免使用。
引起混淆的加号、减号
不要在 + 后面跟另一个 + 或 ++,因这种做法会引起混淆。而是应该加上 **( ) ** ,以清晰表达你的意图。
total = subtotal + +myInput.value;
最好改写为:
total = subtotal + (+myInput.value);
如此,+ + 就不会误读为 ++。
eval是恶魔(eval is Evil)
eval 函数是JavaScript中最被误用的,不要用它。
eval 有别名。(不很懂)
不要使用 Function 构造函数。(不很懂)
不要给 setTimeout setInterval 传字符串。
用心编程,你也能长满大胡子 ;)
800px-Douglas_Crockford.jpg
网友评论