JavaScript中的糟粕&正确代码规范

633 阅读8分钟

命名

  • 我们应该努力使用顾名思义、一目了然的名称。
  • 以字母开头、以字母结尾。

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

  • 在命名时以下划线开头或结尾通常是为了表示私有属性或者全局私有变量。所以,挂在开头或结尾的下划线是一个程序员不成熟的表现。
  • 美元符号则通常是被一些代码生成器、转义器和宏处理器加到变量里的,以此来保证生成的变量名不会与人工编写的代码冲突。为了证明你并不是一个机器人,离美元符号远一点儿吧。
  • 所有的构造函数都应该以大写字母开头,而其他任何名字都应该以小写字母开头。我们以此来给函数划分语义,从而使一些错误更容易被发现。
  • 以数字结尾的名字通常是程序员因起名而头大的表现。

以下是我公司实习生(同事)留给我代码中的函数命名:

private handleEdit1()
private handleEdit2()
private handleEdit21()
private handleEdit3()
private handleEdit4()
private handleEdit41()
……

是不是看的头都大了?实际上,更为糟糕的是,这些函数代码全都没有注释!

注释

  • 除了命名中就可以很清晰的知道什么作用、代表什么的代码以外,我建议是,全部加上注释。
  • 注释可以帮助交接工作,强化工作效率,而且还利于后期的代码维护。
  • 表单中的每一个参数都需要注释,判断中的变量也一样。

如果有经常用到的参数可以采用定义变量名赋值的方法:

private MallClose = 0
private MallOpen = 1
if(status === MallOpen){……}

当然如果你使用的是typescript的话,还可以使用更为方便的 emun 枚举类型:

enum Color{Red, Blue, Green, Yellow};//值从左到右依次为 0,1,2,3
enum Color{Red=10,Blue,Green};//值从左到右依次为 10,11,12
enum Color{Red,Blue=4,Green,Yellow};//值从左到右依次为 0,4,5,6

保留关键字

Javascript 的保留关键字不可以用作变量、标签或者函数名。有些保留关键字是作为 Javascript 以后扩展使用。下面是JavaScript的保留字列表:

abstractargumentsbooleanbreakbyte
casecatchcharclass*const
continuedebuggerdefaultdeletedo
doubleelseenum*evalexport*
extends*falsefinalfinallyfloat
forfunctiongotoifimplements
import*ininstanceofintinterface
letlongnativenewnull
packageprivateprotectedpublicreturn
shortstaticsuper*switchsynchronized
thisthrowthrowstransienttrue
trytypeofvarvoidvolatile
whilewithyield
  • * 标记的关键字是 ECMAScript5 中新添加的。

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

零是独一无二的。理论上来说,在一个数值系统中只应存在一个零。然而事不遂人愿,在IEEE 754标准中有两个零:0和-0。你知道JavaScript为帮你抹平0与-0的不同做了多大努力吗?它让我们几乎可以忽略-0的存在。不过仍然需要注意以下几种情况:

(1/0) === (1/-0)
// false
Object.is(0,-0)
// false

我真心建议你不要拿零做除数,也永远不要使用Object.is()

NaN

  • NaN是一个特殊值
  • NaN是Not a Number的缩写。
  • 虽然它的含义是“不是一个数”,但是typeof对它的结果又告诉大家NaN是一个数("number")。
  • 当字符串转换成数值失败时,结果就是NaN。此外,当算术表达式中的一个数值为NaN的时候,它的运算结果也会是NaN。

最让人困惑的是,NaN居然不等于它自己!这是IEEE 754的糟粕,JavaScript却将其照搬了过来,没有做任何处理。NaN的相等比较与其他数值的相等比较是不一样的,这会在我们写测试时埋下隐患。当我们用相等判断期望值为NaN的时候,测试总会失败,哪怕实际值真的是NaN。因此,当我们要判断一个值是不是NaN时,应当使用Number.isNaN(value)Number.isFinite(value)函数会在值为NaN、Infinity或者-Infinity的时候返回false。

  • 任意数值与NaN进行任意比较都会返回false。

如果JavaScript一开始就定义好NaN小于所有数,或者在NaN与别的数进行比较的时候直接抛错,就不会有现在那么多问题。然而JavaScript没有这么做,只是返回一些无意义的结果。对于NaN而言,唯一有意义的运算就是Number.isNaN(NaN)。除此之外,不要在任何场景用NaN。

布尔式错误类型

JavaScript虽然有美妙的布尔类型,但是并没有用好它。下面是一些适用布尔类型值的地方:

  • if语句的条件判断位;
  • while语句的条件判断位;
  • for语句的条件判断位;
  • !的操作值;
  • &&两边的操作值;
  • ||两边的操作值;
  • 三元运算符(?:)的第一个操作值;
  • Array的filter、find、findIndex和indexOf方法中传入的函数的返回值。

在一个设计良好的语言中,上述位置应该只允许使用布尔类型。然而JavaScript偏偏没有,它允许任意类型的值存在于这些位置中。下面是js中存在的假值:

  • false
  • null
  • undefined
  • ""(空字符串)
  • 0
  • NaN

这些幻假的值虽然表面上看起来像false,但实际上大多是装出来的。幻真的值也一样。这些犯蠢的类型是设计上的缺陷,但这并不能全怪JavaScript。JavaScript沿用的是C语言的习惯。C语言本身是一门类型不足的语言。0、FALSE、NULL、字符串结束符,还有一些类似东西的值其实都一样。所以在if语句的条件判断位,C语言其实判断的是表达式结果是否为0。C语言程序员有一个流派,就是利用这个“特性”让条件判断尽可能简洁。

跟C语言不一样的是,JavaScript有健全的布尔类型,但布尔式犯蠢类型糟蹋了布尔类型的很多价值。理论上,一个条件判断的结果只应为true或false,其余的值都应该在编译时就抛错。然而JavaScript并非如此,它的条件表达式可以写得如C语言般简洁。当条件判断语句意外地传入了错误类型的值时,JavaScript不会报错。这就很可能让程序进入另一个本不该进入的条件分支。Java就不一样,它要求条件判断位中的值必须是布尔类型,这样可以避免很多潜在的错误。唉,真希望JavaScript也是这样的。

虽然JavaScript并没有学习这些好榜样,但我还是希望你能假装它已经做到了,然后在条件判断位中始终使用布尔类型。如果我们在编码的时候严于律己,就能写出更好的程序。

排序

JavaScript有一个sort方法。然而,这个方法存在不少问题。

  • 排序方法是原地生效的——它会修改原数组。也就是说sort方法无法对冻结数组进行排序,而且对共享型数组(shared array)进行排序操作也不安全。
  • sort方法的默认比较函数会将所有比较对象都转成字符串,即便里面的元素都是数。

这种“特性”不仅拖慢了性能,而且是一个明显的设计错误!不过总算天无绝人之路,我们还能自己给sort方法传入一个比较函数。自定义比较函数接收两个参数。在比较大小的时候,如果认为第一个参数应当排在第二个参数前面,则自定义比较函数需要返回一个负数;如果第二个参数应当排在前面,则需要返回正数;如果自定义比较函数返回0,则表示比较函数无法判断孰大孰小。

中断

我个人最喜欢的中断语句是return。它会中断函数的运行,并指定返回值。学校教导我们,一个函数只应该有一个return语句。然而我从未见过任何证据表明这种理论是有益的。我认为更有意义的说法应该是在使用return的时候确信目前应当返回,而不是将所有的返回点集中到一处。

  • JavaScript并没有goto语句,但是允许所有的语句有标记(label)。

===

很多笑话都是JavaScript的==+运算符背后的强制类型逻辑闹出来的。强制类型规则非常复杂难记,而且在某些情况下是错误的。这就是我不推荐使用==的原因。它实现了ECMAScript的抽象相等比较算法(abstract equality comparisonalgorithm),是一罐不建议大家打开的“鲱鱼罐头”。请记住一定要用===。一定!

有些开发者不喜欢用===,因为它看起来比==愚蠢50%,比=愚蠢3倍。无论如何,在JavaScript中,===才是正确的相等判断运算符。请避免使用==,用它判断相等就大错特错了。