JavaScript使用生成器时不写分号出现的问题
问题
下面是一段斐波那契数列的生成器代码
javascript
function* fibonacciSequence() {
let x = 0, y = 1;
for(;;) {
yield y;
[x, y] = [y, x + y];
}
}由于我平时写js的习惯是不写分号,所以我在敲上面那段代码时去掉了分号
javascript
function* fibonacciSequence() {
let x = 0, y = 1
for(;;) {
yield y
[x, y] = [y, x + y]
}
}此时我想要知道第20个斐波那契数,于是写下这段代码
javascript
function fibonacci(n) {
for(let f of fibonacciSequence()) {
if(n-- <= 0) {
return f
}
}
}此时调用方法发现结果是
javascript
fibonacci(20) // => [ 1, 1 ] 与预想的结果不符合而正常的第20个斐波那契数应该是10946
要知道JavaScript解释器是有ASI(Automatic Semicolon Insertion)机制的,即自动插入分号,那两段代码只有分号的区别,初步判断是ASI没有照着期望的方向添加分号
于是通过Esprima Parser将js的语法树解析出来看看之后发现
不加分号的yield语句后面跟的是赋值表达式
而加分号之后的yield语句后面是标识符
ASI规则
ECMAScript 标准定义的 ASI 包括三条规定和两条例外。
三条规则
- 解析器从左往右解析代码(读入
token),当碰到一个不能构成合法语句的token时,他会在以下几种情况中,在该token之前插入分号,此时不合群的token被称为违规 token(offending token)- 1.1 如果这个
token跟上一个token之间有至少一个换行。 - 1.2 如果这个
token是}。 - 1.3 如果前一个
token是)它会试图把签名的token理解成do-while语句并插入分号。
- 1.1 如果这个
- 当解析到文件末尾发现语法还是无法构成合法的语句,就会在文件末尾插入分号。
- 当解析碰到
restricted production的语法(比如return),并且在restricted production规定的[no LineTerminator here]的地方发现换行,那么换行的地方就会被插入分号。
两条例外
分析
根据ASI规则可知JavaScript解释器解析到yield语句时
第一个token是“y”第二个token是“[”不满足添加分号的条件
于是上面不加分号的代码就会被解析为
javascript
function* fibonacciSequence() {
let x = 0, y = 1;
for(;;) {
yield y[x, y] = [y, x + y];
}
}所以和预想的不符合
2022/12/12