关于JavaScript语句后面的分号
身为一个分号党,我就不在唠叨自己的看法了,为了让我们的讨论更有价值,我挖掘出来一些材料跟各位分享。
JavaScript自动加分号规则,有3条
- 当有换行符(包括含有换行符的多行注释),并且下一个token没法跟前面的语法匹配时,会自动补分号。
- 当有}时,如果缺少分号,会补分号
- 当程序源代码结束时,如果缺少分号,会补分号。
利用我自己的JS语法分析工具JSinJS(https://github.com/kissjs/JSinJS ),我求出了所有能够出现在语句第一个的JS语法标记 (就是Statement的first集合),他们是:
["debugger", "try", "throw", "switch", "Identifier", "with", "return", "break", "continue", "for", "while", "do", "if", "new", "function", "(", "{", "[", "RegularExpressionLiteral", "StringLiteral", "NumericLiteral", "BooleanLiteral", "NullLiteral", "this", "!", "~", "-", "+", "--", "++", "typeof", "void", "delete", ";", "var"]
我又求出了所有可以出现在分号之前的语法标记(即去掉分号以后的last集),他们是
["--", "++", "IdentifierName", "]", ")", "}", "RegularExpressionLiteral", "StringLiteral", "NumericLiteral", "BooleanLiteral", "NullLiteral", "Identifier", "this", "debugger", "return", "break", "continue"]
共计17个。
35*17 = 595种组合,为了方便记忆,以下我分组来讨论语法歧义 。(本来用Excel弄了张表,不过表太大了不好贴出来)
首先,以下语法标记开头的语句是绝对安全的,不会跟不加分号的上一行产生任何歧义:
var if do while for continue break return with switch throw try debugger ;
接下来我们来分组看不加分号导致的语法歧义:
- 第一种是++和--两种运算符出现在上一行结尾的情况,下一行以以下开头时,会产生语法歧义:
function delete void typeof new null true false NumericLiteral StringLiteral RegularExpressionLiteral ( [ { Identifier ++ -- + - ~ !
其中,function和delete是非常常用的statement开头。
特别是 ++和--单独被断为一行的时候,因为JS的语法规则规定后自增运算不允许中间插入换行,所以++和--会被视为前自增而跟下一行连接在一起。 - 第二种是return作为上一行结尾的情况,下一行以以下开头时,会产生语法歧义:
function delete void typeof ( [ { Identifier ++ -- + - ~ !同样因为JS语法的规则不允许在return 和后面的值之间插入换行,所以return之后只要有换行符就会视为有分号,这常常会与使用者的期望不符合。 - 第三种是下一行以+和-开头的情况,上一行以以下结尾是,会产生语法歧义:
-- ++ IdentifierName ] ) } RegularExpressionLiteral因为很少有语句以+或者-开头,所以这种情况不算危险。
- 第四种是上一行以break、continue结尾的情况,下一行以Identifier开头时,会产生语法歧义。
- 第五种是下一行以(和[开头的情况,上一行以以下结尾是,会产生语法歧义:
-- ++ IdentifierName ] ) } RegularExpressionLiteral StringLiteral NumericLiteral BooleanLiteral NullLiteral Identifier this
这种情况非常危险(所以hax的文章中要提出这种情况应该语句前写分号),几乎上一行的所有情况都将导致正常期望之外的结果。 - 第六种是,当下一行以RegularExpressionLiteral 开头的情况,上一行的以下结尾,会导致/被理解为除号:
-- ++ IdentifierName ] ) } RegularExpressionLiteral StringLiteral NumericLiteral BooleanLiteral NullLiteral Identifier this
总结,
- 在return、break、continue、后自增、后自减五种语句中,换行符可以完全替代分号的作用。
- var if do while for continue break return with switch throw try debugger几种关键字开头的语句,以及空语句,上一行加不加分号影响不大。
- 凡表达式语句和函数表达式语句,后面不加分号非常危险,情况极其复杂。
- 凡(和[开头的语句,前面不加分号极度危险。
以上是我整理的规则,不包含任何主观论断。加不加分号,终究还是各位看官自己决定。
练习题:
说出以下语句自动加分号正确的位置:
a + b
a ++ b
this.a = o.a /[0-9]*/g.match(string)
function f() { return /* */ x }
(function f1(){})() (function f2(){})()
obj. if(a)/3/g .test(str)
this.call() [1,2,3].forEach(function(e){ console.log(e); })
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库