Semicolons in JavaScript is optional

100
TaoAlpha
2014-11-053479 words10 minutes to read

JavaScript作为脚本语言的一种, 其末尾的结尾符号:分号, 其实是可选的, 没错, 这个分号并非是强制要求的.

但是, 对这一点很多人有着非常多的担忧啊, 顾虑啊, 不确定啊等等, 也就导致绝大多数的开发者都会推荐我们始终以分号结尾, 以防万一.

那我们究竟在防止什么? 我搜集了一些关于开发者们为什么愿意强迫自己使用分号结尾的原因, 下面我就概括的说下:

规则过于神秘而且JavaScript本身编译器之间又有很多不同

对一个粗略浏览的读者而言, 即使很难理解,明白, 但是关于自动插入分号的规则依然是随处可见的. 而对于JS不同的编译器而言, 又存在很多的区别, 我这恰好有这么个例子. 当我问一些开发者关于为什么使用分号时, 通常他们会这么回答:"哦,有那么一个浏览期就不能正常的编译, 我就是想不起来是哪个了." 当然, 他们永远也不会想起来的...

我自己写JS基本不用分号的, 就个人经验而言, 还没遇到无法处理的JS编译器呢.

如果不用分号就不能压缩JS代码

对JS源文件而言, 压缩其实共分为3个层次: 压缩(比如gzip), 最小化(即去除不必要的空格和注释) 以及模糊化(修改代码, 缩短变量名以及函数名).

类似gzip这类的压缩是最为容易的, 只需要在服务器上设置一次就行了, 完全不需要开发者在进行什么别的代码修改. 曾经IE6在一段时间内不支持这一设定, 不过我记得应该在几年前就已经打补丁修正了, 如今基本没有人会在意这部分了.

最小化和模糊化都会对你的源码有一定的修改. 它们都算是一类你可以用于操作js文件, 用以压缩文件大小, 同时不改变代码本身功能的工具. 我比较不喜欢用这类的工具, 因为很多开发者都说如果我不按照特定的代码格式来编写代码的话, 比如使用分号结尾, 那么这些工具就有可能破坏我的代码. 我完全可以理解以及接受他人或者社区规定使我使用特定的代码格式, 但无法接受一个工具要强迫我使用某种代码格式.

如果我有一段在我目标浏览器或者编译器上运行的代码, 而我通过你的压缩工具压缩后, 它无法运行了, 那么我只能很伤心的告诉你, 你的工具有问题. 如果一个工具想要编辑JS代码的话, 那么, 它最好还是按照真正的编译器理解的那样来进行.

既然说到最小化问题, 我们就简单做个实际的测试吧. 我利用的是jQuery的源码, 当然, 去掉了所有的分号, 然后我在Google Closure Compiler上运行了以下, 将它压缩到76673bytes. 原始的jquery.min.js文件大小在76674(只多了1byte). 所以你可以发现, 基本上是没有区别的; 当然, 它的功能也是完全正常的.

这是如何发生的呢? 我们可以参考下面的代码:

var a=1 var b=2 var c=3

它有24bytes. 给它加上分号后进行压缩: var a=1;var b=2;var c=3; 还是24bytes. 所以, 你可以看到, 添加分号移除空行后对我们的文件大小并没有产生任何的改变. 从根本上来说, 我们通过最小化减少的文件大小并不是通过移除空行所得的, 而是通过移除注释部分获得的.

更新: 很多人都指出他们的最小化工具把上述代码重写为了var a=1,b=2,c=3. 我知道有些工具是这么干的, 但是本文的主旨仅在于探究分号和空行的关系. 而如果一个最小化工具都可以重写代码(比如Closure Compiler), 那么对于它而言, 自动添加分号自然不成问题了.

同样的, 有些人推荐在块结构上使用括号, 即使块结构只有一行代码时: // before if(condition) stuff() // after if(condition){ stuff() } // after minification if(condition){stuff()} 强制使用括号至少能给我们的表达式增加1byte, 即便是压缩后也一样. 我实在不知道这样做的好处在哪里--既不利于文件大小, 也不利于可读性啊.

以下都是一些空格有具体意义的语言, 你可能听过其中的一些:

  • Ruby -- 把操作符,调用函数和空格联合使用的话会抛出异常的;
  • Python - 更不用说了
  • HTML - 可以通过Kangax's HTML minifier了解更多
  • Haml Templates

当然, 针对最小化, 在服务器端我们就不需要进行任何操作了. 我列举这些主要目的是为了支持下面这一论述: 空格可以, 而且经常作为一个语言的一部分. 它并不是一个非要去除不可的坏东西.

这是一个优秀的代码格式

也通常可以理解为:

当然这也算是"其他人都这么做"的另一种表达方式, 很多人在线上讨论时自己没有观点时往往这么说.

至于JSLint, 我能给的建议就是: 不要用了. 为什么要用它呢? 如果你相信它能帮助你, 减少你代码中的bug数目, 那么请听这条快讯: 只有人可以发现并解决软件中的问题, 而不是工具. 所以, 与其使用工具, 不如让更多人看看你的代码.

至于所谓Douglas Crockford所说的"4个空格"论, 还有很多流行的JS库用的要么是tab要么是2个空格呢. 不同项目的社区自然有着不同的观点, 这就是现实, 就如我之前说的: 让其他人以及你自己来塑造你的代码风格, 而不是某个人或者某个工具.

你可能注意到本文中, 我并没有告诉你说你应该彻底扔掉分号. 我只是陈列一些事实告诉你你可以这么做. 具体如何选择还要看你自己.

至于说代码风格, 它们的存在使得代码更加可读, 更加容易被团队中的人理解. 深入的想想分号是否真的可以提升你的代码的可读性. 其实多数情况下, 提升你代码可读性的是空格--缩进, 代码块之间的空行, 对齐表达式时使用的空格等, 以及非常易于理解的变量和函数名. 你可以看看这些非常难懂的代码, 里面总是有很多的分号的. 它帮助你更好的阅读了吗? 没有, 实际上帮助到你的是大量使用的空格以及那些初始变量名.

在return中插入分号会反咬你一口哦

我在搜索"JavaScript分号插入"时, 很多博文中都描述了这么一个问题: function add() { var a = 1, b = 2 return a + b }

在你费解于为什么有人会把代码写成这么个样子之前, 我们先继续看问题, 这段代码会被最小化为:

return; a + b;

显然它并没有返回我们要的求和. 但是你知道吗? 如果我们在a+b后面添加一个分号并不能解决问题. 而当我们去除了return和a+b之间的空行后, 问题就可以解决了.

return a+b

同样的, 利用这一个极端无知的例子, 我还是建议人们不要在代码中随意添加分号. 当然, 分号可能仅仅只是在这一个问题上有问题, 但是我们要做的其实是更好的理解一个语言是如何被解析的.

不加分号的编码中唯一的问题

下面这个例子是你在尽量少用分号的编码方式中需要注意的一种情况:

// careful: will break a = b + c (d + e).print()

它正常的结果应该是:

a = b + c(d + e).print();

这一例子取自一篇关于JS2.0兼容性问题的文章, 但是我确实在我自己使用the module pattern的程序中遇到过几次.

简单的解决办法是: 当某一行是以括号开头的时候, 可以在括号前面加一个分号.

;(d + e).print()

这可能看起来不那么优雅, 但是确实可以解决问题. Michaeljohn Clement 做了进一步的解释:

如果你选择尽可能少的使用分号, 我的建议是在任何一个括号和方括号为开头的表达式前立刻插入一个分号, 或者任何一个以算数运算符 '/','+','-'开头的表达式也应该如此, 如果你正好写了这么一个表达式的话.

接受这一建议就不会有问题了.

Source: