《编写可维护的JavaScript》读书笔记

169 阅读5分钟

第一部分 编程风格

第3章 语句和表达式

在JavaScript中,如iffor之类的语句有两种写法,一种是使用花括号包裹的多行代码,另一种是不使用花括号的单行代码。比如:

// 不好的写法,尽管这是合法的JavaScript代码
if(condition)
    doSomething();
    
// 不好的写法,尽管是合法的JavaScript代码
if(condition) doSomething();

// 好的写法
if (condition) {
    doSomething()
}

// 不好的写法,尽管是合法的JavaScript代码
if (condition) { doSomething() }

不论块语句包含多行代码还是单行代码,都应当总是使用花括号,因为省略花括号会造成一些困惑。

所有块语句都应当使用花括号,包括:

  • if
  • for
  • while
  • do...while...
  • try...catch...finally

3.1 花括号的对齐方式

花括号的对齐风格,主要有两种。一种是将左花括号放置在块语句中第一句代码的末尾,比如:

if (condition) {
    doSomething();
} else {
    doSomethingElse();
}

另一种风格是将做花括号放置于块语句首行的下一行。比如:

if (condition)
{
    doSomething();
}
else
{
    doSomethingElse();
}

作者个人推荐使用第一种。

3.2 块语句间隔

块语句间隔主要有三种风格。第一种风格是,在语句名、圆括号和左花括号之间没有空格间隔。

if(condition){
    doSomething();
}

第二种风格是,在括左圆括号之前和右圆括号之后各添加一个空格,比如:

if (condition) {
    doSomething();
}

第三种风格是在做圆括号后和右圆括号前各添加一个空格,比如:

if ( condition ) {
    doSomething()
}

作者推荐第二种风格,这种风格是第一种和第三种风格的折中。

3.3 switch语句

3.3.1 缩进

switch(condition) {
    case "first":
        // 代码
        break;
        
    case "second":
        // 代码
        break;
        
    case "third":
        // 代码
        break;
        
    default:
        // 代码

}

以上这种风格的特点有:

  • 每条case语句相对于switch关键字都缩进一个层级。
  • 从第二条case语句开始,每条case语句前后各有一个空行。

另一种风格:

switch(condition) {
case "first":
    // 代码
    break;
case "second":
    // 代码
    break;
case "third":
    // 代码
    break;
default:
    // 代码
}

这种写法与前一种写法的主要不用之处在于,case关键字保持和switch关键在左对齐,并且没有空行的存在。

3.3.2 case语句的“连续执行”

swith(condition) {
    
    // 明显的依次执行
    case "first":
    case "second":
        // 代码
        break;
        
    case "third":
        // 代码
        
        /* fall through */
    default:
        // 代码
}

在这段switch语句中,有两个明显的“连续执行”,程序执行完第一个case后会继续执行第二个case,我们认为这种逻辑是合理的。

第二个例子是case third执行后继续执行default里的逻辑。这个过程已经在注释中明确说明了,这是程序编写者故意为之。

作者建议,只要是有意为之并且添加了注释,就可以使用case语句的连续执行。

3.3.3 default

很多人认为不论何时都不应该省略default,哪怕default什么也不做。

作者更倾向于在没有默认行为并且写了注释的情况下省略default:

switch(condition) {
    case "first":
        // 代码
        break;
        
    case "second":
        // 代码
        break;
        
    // 没有default
}

3.4 with语句

with语句可以更改包含的上下文解析变量的方式,通过with可以用局部变量和函数的形式来访问特定对象的属性和方法,这样就可以将对象前缀统统省略掉。

在严格模式中,with语句是被明确禁止的,作者也强烈推荐避免使用with语句。

3.5 for循环

for循环有两种一种是传统的for循环,另一种是for-in循环。

传统的for循环往往用于遍历数组成员,有两种方法可以更改循环的执行过程(除了使用return或throw语句)。第一种方法是使用break语句,立即退出循环,第二种是使用continue,使用continue可以立即退出(本次)循环,而进入下一次循环迭代。

Crockford的编程规范不允许使用continue。他主张代码中与其使用continue不如使用条件语句。

作者推荐尽可能避免使用continue,但也没有理由完全禁止使用,它的使用应当根据代码可读性来决定。

当使用了continue时,JSLint会给出警告,而JSHint不会给出警告。

3.6 for-in循环

for-in循环是用来遍历对象属性的。

for-in循环有一个问题,就是它不仅遍历对象的实例属性,同样还遍历从原型继承来的属性。当遍历自定义对象的属性时,往往会因为意外的结果而终止。出于这个原因,最好使用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(),除非你想查找原型链,这是就应当补充注释。

关于for-in循环,还有一点需要注意,即for-in循环是用来遍历对象的,一个常见的错误用法是使用for-in循环来遍历数组成员。