一行过长的代码会影响阅读体验. 实际项目中,我们往往把过长的代码分成多行去写.
比如在js中, promise链经常要分成多行写. 对此本人想到一个问题, 就是js中, 在什么地方换行是合法并且不破坏原有代码逻辑的.
探究这个问题过程中本人造了一个小玩具, breakline, 顾名思义, 它的作用就是在不破话代码的逻辑的情况下把js代码拆成多行. 项目地址:https://github.com/flowmemo/b...
我们接下来还是谈换行的问题. 为了简单起见, 本文不讨论注释中的换行符.
换行符的作用
在一般的语言中, 换行符一般是意味着一个statement1的结束, 分号也通常有这个作用. 但是js中换行符并没有代表statement的结束的意思. 事实上在规范中, 换行符(规范中称为line terminator)在多数情况下和空格、tab的作用是一样的, 是为了分隔token以及方便阅读, 除了...
换行符在某些情况下会触发自动分号插入(Automatic Semicolon Insertioin, 以下简称ASI)
换行符本身是token的一部分, 比如在StringLiteral(单/双引号字符串, 必须通过
`来escape), Template和TemplateSubstitutionTail(这两个就是*
*包起来的字符串)中.
以下为ECMA-262 7.0(也就是ES7、ES2016)规范中相应的描述:
A line terminator cannot occur within any token except a StringLiteral, Template, or TemplateSubstitutionTail. Line terminators may only occur within a StringLiteral token as part of a LineContinuation.
有了这些信息, 我们就应该知道在什么情况下可以换行了:只要你的新加的换行符不在上述的两个规则内就行.
我们再继续探究这两个规则.
ASI
EMCA规范中有一部分专门讲了ASI, 在http://www.ecma-international...
对于ASI这里就不展开细讲了, 这里只说ASI和换行相关的部分.
Offending Token
一个情况是, 换行符后的token和之前的token一起进行parse会出错, 那么换行符后的token叫做offend token. Offend token前会自动插入一个分号.
举例:
var foo
foo = 2
一共5个token, 按先后顺序是var
, foo
, foo
, =
, 2
. parser先解析了前两个token, 很好, 没错, 然后接着parse下一个token foo
, 出错了(因为没有一个js语法中并没有一条production包含var foo foo
的形式). 于是ASI被触发, 在换行符和offend token间加了个分号. var foo
就被parse成了Variable Statement, 然后后面的foo = 2
也被成功parse了2.
Restricted Production
Restricted production规定了触发ASI的几种特殊情况.
以下几个位置出现换行符, 即使之后的token可以继续被合法parse, 也会触发ASI
后缀自增/自减运算符之前
continue, break, return, throw, yield之后
arrow function的
=>
之前
所以我们要比尽量避免在上述位置加换行符(除非你知道自己是在做什么).
Template和TemplateSubstitutionTail
这部分简而言之就是不要在表示字符串内容的部分换行. 这个很好理解了.
需要注意的是对于有替换的部分, 也就是${}
的花括号内部,是可以当作普通的expression换行的
也就是说
var s = `hello ${person.name}!`
var s = `hello ${
person
.
name
}!`
是相同的.
玩具:breakline
在探究这个过程中本人写了breakline. 这个工具的目的就是把你的js代码拆成多行, 同时又不对代码的功能和逻辑造成实质的影响.
总结
在实际写代码过程中, 符合普通人逻辑的“正常”的换行是没有问题的. 如果说有需要注意的地方,也就是restricted production的第二条了, continue, break, return, throw, yield这几个关键字以及=>
后不要换行, 其他的地方换行的话...可以说也没什么美感了, 一般人不会那么干的.
注
[1] 关于statement和expression的区别, 可以参考http://www.2ality.com/2012/09...
[2] 实际上在foo = 2
后也自动插入了一个分号.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。