浏览 3301 次
锁定老帖子 主题:JavaScript的EOS(分号)问题
精华帖 (0) :: 良好帖 (7) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-05-08
http://bbs.51js.com/viewthread.php?tid=83937&extra=page%3D1&page=1的讨论中,月影分析了JavaScript中EOS(End of Statement)存在的歧义问题。下面是我的回应。
在是否要写“;”呢? 我经过几次反复。最开始是随便,想写就写。 后来都不写。 后来有段时间都写。 现在又都不写。 基本上现在的结果是我最后定型的习惯了。 原因: 1. 程序如果不追求太紧凑(例如要把多个语句写到一行里),分号确实是可以不用的。而且强制自己不用分号,其实是强制自己不要使用紧凑风格。 2. c-style的分号本来就是多余的。为什么这么说?因为明确的EOS只是给编译器的提示而已。而如果漏了分号,编译器会报错。既然它都报错了,显然它知道这里应该有EOS。既然它知道,那么干嘛还要我写? 某人说:【No expert programmers *hate* the situation in which the compiler throws out the program because of a missing semicolon. They ask the very reasonable question "if the compiler knows there should be a semicolon there why the **** doesn't it put it in?"】 所以明确的EOS只是给编译器的hint而已。这在几十年前是一个平衡编译器和用户成本的设计。但是放到现在,就未必了。JS以及许多语言的可选分号或可选EOS,其实就是一种回归。 3. 但是JS的严重问题是,它要兼顾(主要是兼顾从java那里继承下来的c-style的跨行语句习惯)。所以分号自动插入算法导致的实际结果是:EOS可能是分号,也可能是换行。麻烦的是,换行不一定是EOS。换行是否是EOS要看这一行和下一行结合起来。如果加上点括号啊,注释之类的,那到底EOS在哪里就头大了。 4. 所以问题仍然和最初类似,现行的JS的EOS规则,是为编译器(JS解释器)设计的(尽管初衷是为人的方便),而不是为“人”设计的。 5. 一个可供比较的例子是Groovy。它也是允许不写分号的。但是它的规则更好。基本不太会出现很难判断一个换行是否是EOS的例子。参见我的老文章:Groovy在EOS问题上的痛苦权衡 6. 本身js的规则也不能说太差,但是最让人反感的,是对括号的处理。也就是月影所举的一系列例子。假如不是因为对于括号处理的愚蠢设计,js的分号处理完全是可以接受的。 7. 所以如果像我一样,完全不写分号,就必须做到不在语句开始使用“(” 、“[”和其他歧义符号(如“+/-”)。这种情况本来也是比较少的。如对于(function...)的惯例法,可用void function或者new function来替代。 8. 其实出现歧义的情形,后续语句都是一个被丢弃结果的表达式(有例外的情形吗?),所以基本上可以在语句开始加上void运算符来明确,并且消除歧义。当然,更简单的方法是在引起歧义的语句之前(而不是之后)加上“;”。 总之,现在的状况是js的设计失误,如果没有工具支持(比如预处理器来补上“;”),那么从最佳实践的角度出发,就两种选择: 1. 月影的做法 每个语句之后写“;” 优点:作为规范,描述起来比较简单 缺点:老是要写烦人的“;” 陷阱:要记得,function表达式后面也要写“;” 另外,应该尽量避免写出有歧义的跨行语句,因为很难判断是有意为之,还是忘记写“;”。 2. 偶的做法 采用更严格的跨行策略,即只允许在当前行处于未完成状态时跨行(就像你在jsshell中输入代码一样)。 对于可能引起歧义的语句(行首为(、[、+/-等),在句首加上 void 或 “;”。 优点:省略了很多无聊的“;” 养成更良好的跨行代码习惯(适用于所有c-style的语言) 更容易应用工具(比如预处理器可以扫描出所有有问题的行,而对于传统的行尾加分号,工具只能warning,因为无法判断到底是有意跨行,还是忘记写“;”) 缺点:要判断歧义语句,另外在语句首加上void或“;”有点难看 陷阱:暂时没有发现 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-09-24
不用分号的话,在minify以后可能会出错吧。
|
|
返回顶楼 | |
发表时间:2009-09-24
每行写;结尾 有点累 虽然现在养成的习惯 每行都写 不过可以少写几个 按逻辑块划分 一个逻辑块完成了 加个; 表示一个逻辑完成了 比如 if...else... for.... function 等
|
|
返回顶楼 | |
发表时间:2009-09-24
那是minify工具没有做好。
|
|
返回顶楼 | |
发表时间:2009-12-08
YUI Compressor对省略分号的代码也不能正常压缩。。敢问hax用啥压缩工具啊?
|
|
返回顶楼 | |
发表时间:2009-12-09
你可以用jindw的JSA。参考:http://www.iteye.com/topic/406387
|
|
返回顶楼 | |
发表时间:2009-12-24
YUI Compressor有问题。今天遇到一个诡异问题。1个js文件尾部有如下代码:var func = function(){//...}没有以分号结尾。另外一个js文件代码是这样的:(function(){})(arg); 这2个文件组合压缩成单行后就会自动执行func,就会触发不可预料的问题(如dom未加载时访问了dom)。所以还是严格点好,所有表达式结尾都加分号。这个问题太巧合了!
|
|
返回顶楼 | |
发表时间:2009-12-24
最后修改:2009-12-24
上面这个问题是存在的。所以这也是javascript语法的一个设计缺陷。
我个人建议,不是结尾都加分号(这个也不能确保别人都这样做)。而是在(...)这类括号开头的代码前主动加分号,这样你的正确性不依赖于别人。 详细的分析见:http://hax.iteye.com/blog/382186 |
|
返回顶楼 | |
发表时间:2010-02-21
鹤惊昆仑 写道 YUI Compressor有问题。今天遇到一个诡异问题。1个js文件尾部有如下代码:var func = function(){//...}没有以分号结尾。另外一个js文件代码是这样的:(function(){})(arg); 这2个文件组合压缩成单行后就会自动执行func,就会触发不可预料的问题(如dom未加载时访问了dom)。所以还是严格点好,所有表达式结尾都加分号。这个问题太巧合了! hax 写道 你可以用jindw的JSA。参考:http://www.iteye.com/topic/406387 合并压缩的问题。JSA对合并压缩至支持JSI工程导出处理。 对普通js压缩没有提供多文件支持,你得自己合并后压缩。安全起见,你可以文件之间用"\n;"分割 。JSA会自动删掉多余的";"号的 |
|
返回顶楼 | |
发表时间:2010-02-21
最后修改:2010-02-21
我的做法是变量形式的加;,传统if、for、while、function都不加;。
var func = function() { }; //加 var obj = {}; //加 obj.abc = function() { }; //加 function func() { } //不加 var obj = { }; //加 if () { } //不加 for () { } //不加 |
|
返回顶楼 | |