计算机程序是人类制造出来的最复杂的事物。程序通常由很多部分组成,表现为函数、语句和表达式,它们必须准确无误地按照顺序排列。最终的结果几乎都和实现它的程序没有什么相似之处。在软件的产品生命周期中,通常它们都会被修改。把一个正确的程序转化为另一个同样正确但风格不同的程序,是一个极具挑战性的过程。
优秀的程序拥有一个前瞻性的结构,它会预见到未来所需要的可能修改,但不会让其成为过度的负担。优秀的程序也有一种清晰的表达方式。如果一个程序被表达得很好,那么我们就能更加容易地去理解它,以便成功地修改或修复它。
这些观点适用于所有的编程语言,且对JavaScript来说尤为正确。JavaScript的弱类型和过度的容错并没有给程序质量带来什么编译时的保证,所以为了弥补,我们更应该按照严格的规范来进行编码。
软件的长期价值是和代码库的质量成正比的。在程序的生命周期里,会经历很多人的检测、使用和修改。如果一个程序能很清楚地传达它的结构和特性,那么当它在并不遥远的将来被修改时,它被破坏的可能性就小很多。
JavaScript代码经常是直接发布的,所以它就应该自始至终具备发布质量。整洁是会带来价值的。通过在一个清晰且始终如一的风格下编写,你的程序会变得易于阅读。
事实证明代码风格在编程中是重要的,就像文字风格对于写作是重要的一样。好的风格促使代码能被更好地阅读。
计算机程序有时被认为不是用来读的媒介,所以只要它工作,写成怎样是不重要的。但是结果证明,如果程序具有可读性,将显著增强它正常运行的可能性,以及是否准确按照我们的意图去工作的可能性。它也决定了软件在其生命周期中是否能进行扩展性修改。如果我们能阅读并且理解程序,那么就有希望去修改和提高它。
整本书我始终采用一致的风格。我的目的是使代码实例尽可能地易于阅读。我始终使用空白来给你更多关于程序的含义的提示。
我在每行最多放一个语句。在一行里放多条语句可能会被误读。如果一个语句一行放不下,我将在一个冒号后或二元运算符后拆开它。这将更好地防止复制/粘贴时被IDE错误地自动插入分号。我给折断后的语句的其余部分多缩进4个空格,如果4个还不是很明显,就缩进8个。
我始终在结构化的语句中使用代码块,例如if和while,因为这样会减少出错的几率。我曾看到过:
if(a)
b();
变成:(默然说话:记住,在现实中,修改是一种常态,别以为你会永远都不会修改某个if或while语句)
if(a)
b();
c();
这是一个很难被发现的错误。它看起来像是这样:
if(a){
b();
c();
}
但它其实是:
if(a){
b();
}
c();
看起来想要做一件事情但实际上却在做另一件事情的代码通常都导致bug。一对花括号可以很低廉的解决那些需要昂贵的代价才能发现的bug。
我一直使用K&R(默然说话:什么叫K&R?你不是正在上网么?为啥不Google一下?)风格,把大括号{放在一行的结尾而不是下一行的开头,因为它会避免在JavaScript的return语句中的一个可怕的设计错误。
我的代码包含了一些注释,我喜欢在程序中放入注释来留下一些信息,以后,它将会被那些需要理解我当时思路的人们(也可能就是我自己)阅读。有时候觉得注释就像一个时间机器,我用它发送重要的信息给未来的我。
我会努力保持注释是最新的。错误的注释甚至可能会使程序更加难以阅读和理解。我不能容忍那样的错误。
我尽量不用类似这样的无用注释去浪费你的时间:
i=0;//设置i为0
在JavaScript中,我更喜欢用行注释。我将块注释用于正式的文档记录和注释。
我更喜欢使我的程序结构具备自我说明性(默然说话:也就是我常常说的:代码就是注释性的,这要求变量命名规范且有意义,代码尽量少用复杂难懂的数据算法等等),从而消除对注释的需要。但只要程序还没有完整,我就会写注释。
JavaScript有函数作用域,但没有块级作用域,所以我在每个函数的开始部分声明我的所有变量。JavaScript允许变量在它们使用后被声明。那对我来说感觉像是一个错误,并且我不希望写的程序看起来有错误。我希望我的错误被突出显示出来。例如,我绝不在一个if的条件部分使用赋值表达式,因为:
if(a=b){…}
可能的本意是:
if(a===b){…}
我想要避免那些看起来像有错误的习惯用法。
我绝不允许switch语句块中的条件贯穿到下一个case语句。我曾经在我的代码里发现了一个无意识的“贯穿”而导致的bug,而在此之前,我刚刚热情澎湃地做完一次关于为什么“贯穿”有时是有用的演讲。能够从经验中学习,我觉得非常幸运。当我现在评审一门语言的特性的时候,我把注意力放在那些有时很有用但偶尔很危险的特性上。那些是最糟糕的部分,因为我们很难辨别它们是否被正确地使用了。那是bug的藏身之地。
JavaScript为大型程序提供了支持,但它也提供了不利于大型程序的形式的惯用法。举例来说:JavaScript为全局变量的使用提供了方便,但随着程序的日益复杂,全局变量逐渐变得问题重重。
我用一个单独的全局变量去包含一个脚本应用或工具库。每个对象都有它自己的命名空间,所以我很容易使用对象去管理代码。闭包的使用提供了进一步的信息隐藏,增强了我的模块。