JavaScript悟道
上QQ阅读APP看书,第一时间看更新

第 1 章 命名 ○ ○ ○ ○ ●

汝知吾名。

——约翰·列侬和保罗·麦卡特尼1

1约翰·列侬和保罗·麦卡特尼是甲壳虫乐队的成员。“You Know My Name (Look Up the Number)”是甲壳虫乐队的一首歌。——译者注

在JavaScript中,你需要给变量、属性以及函数命名。因为JavaScript对于变量名的长度没有限制,所以不要吝惜你的起名才华。我希望你在命名的时候尽可能描述清楚被赋名者的含义,而不要使用各种隐晦的缩写。

我的第一位程序设计老师是名数学家,后来我去了一家使用BASIC的公司工作。那时候,BASIC语言的变量名是一个大写字母,后面可以跟一个数字,如A1。因此,我养成了一个坏习惯,即喜欢使用单字母作为变量名。这个坏习惯伴随了我几十年。一些错误思想一旦成为我们的固化思维,就会变得难以改正。我们应当持续学习,以不断完善自我。数学家喜欢使用各种神秘且充满仪式感的简洁符号。然而,计算机科学并不是数学,它是另一门优雅的艺术。编程时,我们应该努力使用顾名思义、一目了然的名称。

让你的命名以字母开头、以字母结尾吧。诚然,JavaScript的命名能以下划线(_)或者美元符号($)开头和结尾,还能以数字结尾2,但我认为你不该这么做。JavaScript允许我们做很多本不该做的事情。这些命名习惯应该留给代码生成器或者宏处理器,而人类应该去做人类该做的事情。

2实际上,JavaScript命名还能以Unicode字符开头和结尾。——译者注

在命名时以下划线开头或结尾通常是为了表示私有属性或者全局私有变量3。所以,挂在开头或结尾的下划线是一个程序员不成熟的表现。

3因为JavaScript没有私有属性,所以通常只能将对应的公有属性名或者全局变量名加上下划线前缀或下划线后缀来从语义上表示其为私有。——译者注

美元符号则通常是被一些代码生成器、转义器和宏处理器加到变量里的,以此来保证生成的变量名不会与人工编写的代码冲突。为了证明你并不是一个机器人,离美元符号远一点儿吧。

以数字结尾的名字通常是程序员因起名而头大的表现。

我通常给序数变量(first、second等)起thing_nr之类的名字,给基数变量(wun、two等)起nr_things之类的名字。

一个变量名可以由多个单词组成,但变量名中不能存在空格,因此如何组织这些单词就是一个问题。有些人建议使用驼峰命名法,即每个单词的首字母都以大写形式呈现,作为单词之间的分隔界线;有些人则建议使用下划线作为单词的分隔符;还有一种神奇的做法,那就是简单地将所有单词拼起来,忘掉分隔符这回事。业界已经为这些命名法争论了很多年,但目前仍没有达成共识。我觉得这是因为这几种做法都有问题。

最佳实践就应该是在变量名中使用空格。目前已有的大多数编程语言不允许变量名中存在空格,这是因为在20世纪50年代,编译器是在很小的空间中运行的,若变量名中存在空格就太奢侈了。FORTRAN首先打破了桎梏,允许在命名时使用空格。然而,后来包括JavaScript在内的大多数编程语言没有继承这个优良传统,反而学习了它的一些糟粕。例如,使用等号(=)表示赋值,用圆括号(())而不是花括号({})包裹if语句的条件表达式。

我非常期待未来会出现一门编程语言去做一些对的事情,如允许变量名中存在空格以提高代码的可读性。今非昔比,我们现在以吉字节为单位来计量内存容量,编程语言的设计者可以大胆地设计一些东西了。不过在出现这么一门语言之前,我还是推荐你使用下划线分隔变量名中的多个单词。这是因为,万一哪天真有更好的编程语言出现,这种命名法可以让你最便捷地将代码迁移至下一门语言。

JavaScript中的所有名字都应该以小写字母开头,这一切都拜JavaScript中的new运算符所赐。如果一个函数名的前面有new,则代表该函数是一个构造函数,否则它就是一个普通函数。构造函数和普通函数是不一样的,错误地调用构造函数会导致问题。更让人抓狂的是,光从表面上看,构造函数和普通函数并没有什么区别,也就并不存在什么方法可以自动检测出那些“由于错误地加上或者丢失new而造成的问题”。因此,我们应该做这样的约定:所有的构造函数都应该以大写字母开头,而其他任何名字都应该以小写字母开头。我们以此来给函数划分语义,从而使一些错误更容易被发现。

我其实还有一个诀窍:从不用new。如此一来,我甚至可以再也不用以大写字母开头去命名函数了。我推荐你也这么做,因为这个世界上每天都有成堆使用new的粗鄙代码出现,简直可怕。

下面是JavaScript的保留字列表:

arguments await break case catch class const continue debugger default delete do else enum eval export extends false finally for function if implements import in Infinity instanceof interface let NaN new null package private protected public return static super switch this throw true try typeof undefined var void while with yield

千万要记住上面的列表,这是基础中的基础。以上任意单词都不能被用作变量名或者参数名。JavaScript关于保留字的规则非常复杂,上面列表中的一些单词在特殊情况下其实是可以使用的。但我还是那句话:尽量不要尝试各种奇怪的做法,要杜绝将这些单词作为变量名等。

保留字其实是20世纪五六十年代计算机内存空间有限的另一个遗留产物,因为保留字的设计可以给编译器节约少许字节。受惠于摩尔定律,我们现在不必再受这些事情的困扰了。可惜这几十年来,人们的思维已经固化。对于现代程序员来说,保留字的设计真的是糟粕。扪心自问,你能否记住所有的保留字?还有一种糟心的情况是,你在起变量名的时候,尽管有个单词可以完美地阐释该变量的意义,但很不巧,它是一个你从来不用的保留字,甚至是一个还没有被实现的预保留字。此外,保留字对于现代编程语言的设计者来说也不是好东西。脆弱的保留字策略会使我们不能干净利落地为一门流行语言添加新特性,给我们添堵。真希望能有一门强硬的新语言出现,让我们不用再为“五斗保留字”折腰。