了解分号插入的局限性
JavaScript的一个便利是能够离开 语句结束分号 工作。 删除分号后,结果变得轻量而优雅,比如下面这个例子去掉所有分号,JavaScript会自动插入分号。
1 2 3 4 5 6 7 8 9
| function Point(x, y) { this.x = x || 0 this.y = y || 0 }
Point.prototype.isOrigin = function() { return this.x === 0 && this.y === 0 }
|
这段没有分号的代码能够工作依赖于JavaScript的自动分号插入技术(automatic semicolon insertion), 它是一种程序解析技术。它能够推断出上下文省略的分号,然后有效的将分号自动插入到程序中。
像隐式的强制转换一样,分号插入也有其陷阱,你根本不能避免学习其规则, 即使你从来不省略分号,受分号插入的影响,JavaScript语法也有一些额外的限制。一旦学会分号插入机制,你会从删除不必要的分号的痛苦中解脱出来
规则一
分号仅在 } 标记之前、一个或多个换行之后和程序输入的结尾被插入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
function square(x) { var n = +x return n * n }
function area(r) { r = +r; return Math.PI * r * r }
function add1(x) { return x + 1 }
function area(r) { r = +r return Math.PI * r * r }
|
规则二
分号进在随后的输入标记不能被解析时插入 , 换句话说分号插入是一种错误矫正机制。
1 2 3 4 5 6
| a = b (f());
a = b f();
|
有5个明确有问题的字符需要密切注意
**(、[、+、-和/**, 每一个字符都能作为一个表达式运算符或一条语句的前缀, 这依赖于具体上下文。,如果下一行以这五个有问题的字符串之一来时,则不会自动插入分号。向上面的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| a = b ["r", "g", "b"].forEach(function(key) { background[key] = foreground[key] / 2; });
a = b["r", "g", "b"].forEach(function(key) { background[key] = foreground[key] / 2; });
/Error/i.test(str) && fail();
a = b /Error/i.test(str) && fail();
a = b/Error/i.test(str) && fail();
|
又一个例子,这是一个完全正确的例子,因为会自动插入分号
1 2 3 4 5 6 7 8
| a = b var x (f())
var x a = b (f())
|
一个不幸的结果就是,你总是需要注意省略的分号, 并且检查接下来的一行开始的标记是否会禁用自动插入分号。所以你可以采用在**(、[、+、-和/**,字符的开始前置一个额外的分号语句
1 2 3 4 5 6 7 8
| a = b var x ;(f())
var x a = b ;(f())
|
还有一个常用的情况就是脚本连接的情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| (function() {
})()
(function() {
})()
(function() {
})() (function() {
})()
(function() {
})()(function() {
})();
;(function() {
})()
;(function() {
})()
|
最安全的选择就是防御性的增加分号
你可能认为 “我从来不省略分号,我会没事的。” 事实并不是这样。也有一些情况,尽管不会出现解析错误,但是也会强制性的插入分号,
这是所谓的JavaScript的语法限制式(restricted production),它不允许两个字符之间存在换行。
1 2 3 4 5 6 7 8
| return {};
return {};
return; {} ;
|
类似的JavaScript的语法限制产生式包括: return, throw, break, continue, 后置自增或自减运算符。
在return, throw, break, continue, ++, --,参数之前决不能出现换行
关于自增和自减运算符 是为了避免以下代码出现的歧义,
第三条也是最后一条规则
分号不会作为分隔符在for循环空语句头部被自动插入,换言之,for头部里面的;不能省略,必须显示的包含分号
1 2 3 4 5 6 7
| for(var i = 0, total = 1 i < n i++) { total *= i }
|
同样的 while,也是需要显示分号的情况
1 2 3
| function infiniteLoop() { while(true) }
function infiniteLoop() { while(true); }
|