2 Feb 2015

JavaScript语句末尾应该加分号么?

关于JavaScript中行尾分号问题, 由来争议已久.

其中有大师Douglas Crockford以及JSLint的建议一定添加方位分号, 也有很多其他大牛(诸如Zepto的作者)加入了无分号党.

其中孰是孰非也是仁者见仁, 智者见智了.

这篇文章下面会为大家介绍无分号党中代表人物”Mislav Marohnić”对于此问题的阐述.

JavaScript是一门脚本语言, 它的代码段结束符是可选的.

但是, 总是有一群人在质疑这个特性, 这也导致了, 大部分开发人员都会推荐总是包含分号, “仅仅为了安全”.

安全从何而来? 我一直在搜寻开发人员强制添加分号的原因. 下面是我找到的一些原因.


规范含义很模糊并且JavaScript实现存在差异

分号自动插入的规则, 但是要有一个很明确的理解有些困难的.

至于JavaScript的实现中关于这些规则的差异, 好吧, 我还没有找到过.

当我向开发人员咨询或查找讨论资料时, 通常他们的回答都是”浏览器确实崩溃过, 但是我忘了具体情况”, 当然, 他们从未记起过.

我总是编写”无分号代码”, 按照我的经验, 没有发现任何一个JavaScript解释器不能处理这些代码.


没有分号, 无法压缩JavaScript 代码

缩减JavaScript源码文件大小包括三种级别: 压缩(例如gzip), 简化(比如去除不必要的空格及注释), 混淆(改变代码, 缩短变量和函数名).

压缩(Compression)是最简单的, 只需要一次性的服务端配置, 而不需要开发人员额外的工作以及无需代码. 有一段时间IE6是不能处理这种方式的, 但是如果我记得没错, 多年前已经打了补丁并推送了Windows更新, 如今已经没人在意这点了.

简化(Minification)与混淆(Obfuscation)会改变代码. 有很多的工具都标榜着”对于JavaScript文件, 尝试把它们变的更小, 但不会影响功能性”. 对于这些工具, 我是有些抵触的, 因为如果不使用特定的代码格式, 比如添加分号, 它们就会破坏我的代码. 对于社区强制要求特定代码格式的要求, 其实我是ok的, 但不包括这些工具的要求.

设想一段在所有目标JavaScript实现(主流浏览器及一些服务端实现)中可用的代码, 如果压缩工具破坏了我的这段代码, 我会很忧桑的认为那是工具本身是错的. 如果工具编辑了JavaScript代码, 那么它最好像一个真正的解释器来理解代码.

对于压缩这一话题, 让我们做一个显示的检查. 我获取了jQuery的源码并去除了所有的分号, 然后在代码上运行Google Closure Compiler. 结果文件大小为76,673字节. 而jquery.min.js的大小为76,674字节, 仅仅多了一个字节. 正如所见, 几乎没有任何变化, 当然, 测试用例也像之前一样通过了.

为什么会这样? 好吧, 考虑以下代码:

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

这段代码大小为24个字节. 标记上分号, 运行压缩器:

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

依然是24个字节. 因此, 添加分号并去除换行符没有节省任何空间. 大多数节省的空间不是通过删除换行符体现的 - 而是通过删除代码注释和行首缩进实现的.

更新:很多人指出他们的压缩器重写了表达式, 比如var a=1,b=2,c=3. 我知道一些工具会这样处理, 但是此部分的观点只是探寻分号与空格的关系. 如果压缩器有着优秀的表达式重写能力(比如:闭包编译器), 那么意味着它也可以自动插入分号.

还有一些人推荐强制在代码块外使用花括号, 即使只有一行代码:

// before
if(condition) stuff()

// after
if(condition){
	stuff()
}

// after minification
if(condition){stuff()}

即使压缩后, 强制添加花括号也会至少增加一个字节的空间开销. 我不确定这有什么好处 - 对于空间及可读性都没有任何益处.

下面列举出了一些其他空格敏感的语言:

当然, 服务器端代码没有必要进行压缩. 为以下论点我做了这个列表: 空格可以并且总是可以, 部分(标记)语言. 这并不是一件坏事.


优秀的编码习惯

还听到过如下观点:

这是另一种表达”其他人都这么做”的方式, 也常常被在线讨论时理屈词穷的人们用到.

对于JSLint我的建议是: 不要使用它. 为什么要使用它? 如果你深信它会帮助你减少代码中的BUG, 有这样一个观点: 只有能发现并解决软件BUG的人, 没有那样的工具. 因此将工具丢到一边, 让更多的人来阅读你的代码吧.

Douglas Crockford说过”使用4个空格缩进”, 然而大多数流行的JavaScript库都被设置为tabs2个空格. 社区内的不同项目也是存在差异的, 它们就应该是那样. 正如我之前所说: 让人们和你本身形成你的代码风格, 而不是个人或某个工具.

你或许注意到在这篇文章中, 我并没有告诉你们应该坚持”无空格”. 我只是阐述了可以这么做的具体证据. 但是选择权还在你们那.

对于代码风格, 它们的存在是为了提升开发人员对于代码的可读性与易理解性. 请深入思考是否分号提示了你代码的可读性. 对于可读性提示最大的因素应该是:空格缩进, 分隔代码块的空行, 拉长表达式的空格, 以及良好的变量及方法的命名方式. 阅读一些混淆过的代码, 其中包含了分号. 但这对于可读性有任何帮助么? 没有, 而恰恰是大量的空格与最初的变量名起到了真正的作用.


分号插入在返回代码内被吞了

当我搜索”JavaScript semicolon insertion”时, 最多的描述是这样的:

function add() {
	var a = 1, b = 2
	return
	a + b
}

当你绞尽脑汁想明白为什么他们要把return代码另起一行时, 我们可以继续来看这段代码是如何解析的:

return;
a + b;

唉, 这个函数没有返回我们需要的”和”! 但是你猜怎么着? 这个问题不是靠在return表达式末尾添加一个分号(也就是, a+b后面)来解决的, 而是通过删除return后面的换行符解决的:

return a + b

这样的内容真的是很离谱, 这些人建议他们的读者通过添加分号来避免这样的问题. 呃, 好吧, 只是帮助不到到这个特定的例子而已. 我们只需要更好的理解这门语言是如何解析的.


唯一真正的缺陷

这是”无分号”情况下唯一需要注意的地方:

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

这段代码会被执行为:

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

这个例子是取自于JavaScript 2.0 功能兼容性, 但我也在自己的程序中使用这个模型模式运行了若干次.

简单的解决方案: 当一行以圆括号开始时, 给它预置一个分号.

;(d + e).print()

这可能不是很优雅, 但是起到了作用. Michaeljohn Clement甚至研究的更加深入:

如果选择在可能的地方忽视分号, 我的建议是: 在任何代码块中, 只要以开括号((,[])或任意数学运算符(+ - * /)开头, 在符号之前应立即插入一个分号.

将这条建议视为一个规则, 你会受益良多.

注:本文为译文,原文出处Semicolons in JavaScript are optional


Tags:
0 comments