《编写可维护的JavaScript》读书笔记之编程风格-语句与表达式

语句与表达式

在 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 循环不应当用于这种场景。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容