语句与表达式
在 JavaScript 中,诸如 if 和 for 之类的语句有两种写法,使用花括号包裹的多行代码或者不使用花括号的单行代码。
【示例】:
// 不好的写法,尽管这是合法的JavaScript的代码
if(condition)
doSomething();
// 不好的写法,尽管是合法的JavaScript代码
if(condition) doSomething();
// 不好的写法,尽管是合法的JavaScript代码
if (condition) { doSomething(); }
// 好的写法
if (condition) {
doSomething();
}
【建议】:不论块语句包含多行代码还是单行代码,都应当总是使用花括号。
【问题】:省略花括号造成的疑惑,很难看出作者的意图。因为你不知道作者是想满足 condition 条件后,执行下面两条语句而忘记加花括号,还是只想执行第一条语句。
if (condition)
doSomething();
doSomethingElse();
【改进】:这两段代码都有明显的缩进错误,但通过花括号我们可以很快地看出作者的意图,并做出合适的修改。
if (condition) {
doSomething();
}
doSomethingElse();
if (condition) {
doSomething();
doSomethingElse();
}
【建议】:所有的块语句都应当使用花括号。
- if
- for
- while
- do...while...
- try...catch...finally
花括号的对齐方式
Java 风格
将左花括号放置在块语句中第一句代码的末尾。
【示例】:
if (condition) {
doSomething();
} else {
doSomethingElse();
}
【编程指南】:Crockford 编程规范、jQuery 核心风格指南、SproutCore 编程风格指南、Google 的 JavaScript 风格指南以及 Dojo 编程风格指南都出现过。
C# 风格
将左花括号放置于块语句首行的下一行。
【示例】:
if (condition)
{
doSomething();
}
else
{
doSomethingElse();
}
【说明】:当前并无主流的 JavaScript 编程规范推荐这种风格,Google JavaScript 明确禁止这种用法,以免导致错误的分号自动插入。
块语句间隔
【风格一】:在语句名、圆括号和左花括号之间没有空格间隔。
if(condition){
doSomething();
}
【说明】:Dojo编程风格指南推荐使用这种风格。
【风格二】:在左圆括号之前和右圆括号之后添加一个空格。
if (condition) {
doSomething();
}
【说明】:Crockford 编程规范和 Google JavaScript 风格指南推荐。
【风格三】:在左圆括号前后和右圆括号前后各添加一个空格。
if ( condition ) {
doSomething();
}
【说明】:jQuery核心风格指南文档规定了这种风格,因为它使语句中的各个部分都非常清晰和易读。
【建议】:推荐第二种风格,是第一种和第三种风格的折中。
switch 语句
JavaScript switch 语句中可以使用任意类型值,任何表达式都可合法地用于 case 从句。但在其他语言中则必须使用原始值和常量。
缩进
【风格】:Java。
switch(condition) {
case "first":
// 代码
break;
case "second":
// 代码
break;
case "third":
// 代码
break;
default:
// 代码
}
【特点】:
- 每条 case 语句相对于 switch 关键字都缩进一个层级。
- 从第二条 case 语句开始,每条 case 语句前后各有一个空行。
【风格】:Crockford 编程规范和 Dojo 编程风格指南。
switch(condition) {
case "first":
// 代码
break;
case "second":
// 代码
break;
case "third":
// 代码
break;
default:
// 代码
}
【说明】:case 关键字保持和 switch 关键字左对齐,同时在语句中没有空行的存在。
case 语句的“连续执行”
“执行完一个 case 后连续执行(fall through)下一个 case”,这是否是一种广被认可的实践,也是备受争议的一个问题。不小心省略 case 末尾的 break 是很多 bug 的罪魁祸首。如果某个 case 执行结束后直接进入下一个 case,JSLint 会给出警告。
【说明】:很多人认为 case 的连续执行是一种可接受的编程方法,只要程序逻辑非常清晰即可。
switch(condition) {
// 明显的依次执行
case "first":
case "second":
// 代码
break;
case "third":
// 代码
/* fail through */
default:
// 代码
}
- Crockford 编程规范禁止 switch 语句中出现连续执行(fall through)的。
- jQuery 核心风格指南允许 case 的连续执行写法。
- Dojo 编程风格指南给出了在连续执行中添加注释的例子。
【建议】:只要是有意为之并且添加了注释,就可以使用 case 语句的连续执行。
default
【讨论】:switch 语句中另外一个需要讨论的议题是:是否需要 default。
【观点一】:无论何时都不应当省略 default,哪怕 default 什么都不做。
switch(condition) {
case "first":
// 代码
break;
case "second":
// 代码
break;
default:
// default 中没有逻辑
}
【观点二】:在没有默认行为且写了注释的情况下省略 default。
switch(condition) {
case "first":
// 代码
break;
case "second":
// 代码
break;
// 没有 default
}
with 语句
with 语句可以更改包含的上下文解析变量的方式。通过 with 可以用局部变量和函数的形式来访问特定对象的属性和方法,这样就可以将对象前缀统统省略掉。
【示例】:
var book = {
title: "Maintainable JavaScript",
author: "Nicholas C. Zakas"
};
var message = "The book is ";
with (book) {
message += title;
message += " by " + author;
}
【问题】:很难分辨出 title 和 author 出现在哪个位置,也难分辨出 message 到底是局部变量还是 book 的一个属性。实际上这种困惑对开发者的影响更甚,JavaScript 引擎和压缩工具无法对这段代码进行优化,因为它们无法猜出代码的正确含义。
【说明】:在严格模式下,with 语句是被明确禁止的,如果使用则报语法错误。Crockford 编程规范和 Google 的 JavaScript 风格指南禁止使用 with。
【推荐】:避免使用 with 语句,因为你无法将你的代码运行于严格模式之中。
for 循环
for 循环有两种:一种是传统的 for 循环,是 JavaScript 从 C 和 Java 中继承而来;另外一种是 for-in 循环,用来遍历对象的属性。
传统 for 循环
往往用于遍历数组成员。
有两种方法可以更改循环的执行过程(除了使用 return 或 throw 语句)。
- break:不管所有的循环迭代有没有执行完毕,使用 break 总是可以立即退出循环。
- continue:可以立即退出本次循环,而进入下一次循环迭代。
【说明】:
- Crockford 编程规范不允许使用 continue。他主张代码中与其使用 continue 不如使用条件语句。解释说这种方法对于开发者来说更容易理解而且不容易出错。
- Dojo 编程风格指南明确指出可以使用 continue 和 break。
【推荐】:尽可能避免使用 continue,但也没有理由完全禁止使用,它的使用应当根据代码可读性来决定。
【注意】:当使用了 continue 时,JSLint 会给出警告。而 JSHint 不会给出警告。
for-in 循环
for-in 循环是用来遍历对象属性的。不用定义任何控制条件,循环将会有条不紊地遍历每个对象属性,并返回属性名而不是值。
【问题】:for-in 循环不仅遍历对象的实例属性(instance property),同样还遍历从原型继承来的属性。当遍历自定义对象的属性时,往往会因为意外的结果而终止。
【解决】:出于上述问题,最好使用 hasOwnProperty() 方法来为 for-in 循环过滤出实例属性。
var prop;
for (prop in object) {
if (object.hasOwnProperty(prop)) {
console.log("Property name is " + prop);
console.log("Property value is " + object[prop]);
}
}
【说明】:Crockford 编程规范要求所有的 for-in 循环都必须使用 hasOwnProperty()。默认情况下,对于循环体中没有使用 hasOwnProperty() 的 for-in 循环,JSLint 和 JSHint 都会给出警告。
【推荐】:总是在 for-in 循环中使用 hasOwnProperty(),除非你想查找原型链,这时就应当补充注释。
var prop;
for (prop in object) { // 包含对原型链的遍历
console.log("Property name is " + prop);
console.log("Property value is " + object[prop]);
}
【注意】:for-in 循环是用来遍历对象的,而不应该遍历数组成员。
// 不好的用法
var values = [1, 2, 3, 4, 5, 6, 7],
i;
for (i in values) {
process(values[i]);
}
【说明】:该用法在 Crockford 编程规范、Google 的 JavaScript 风格指南中是禁止的,因为这会造成潜在的错误。记住,for-in 循环是用来对实例对象和原型链中的键(key)做遍历的,而不是用来遍历包含数字索引的数组的。因此 for-in 循环不应当用于这种场景。