Javascript分号规则的知识介绍(附示例)


本文摘自PHP中文网,作者不言,侵删。

本篇文章给大家带来的内容是关于Javascript分号规则的知识介绍(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

花点时间搞清楚JS中的分号规则吧~~~不管你喜欢结尾带分号或省略分号的模式

分号允许的场景

分号一般允许出现在大部分语句(statement)的末尾,比如 do-while statement , var statements, expression statements , continue , return , break statement, throw, debugger 等

栗子:

1

2

3

4

5

6

7

do Statement while ( Expression ) ;

 

4+4;

 

f();

 

debugger;

仅有一个分号 ; 可以表示空语句――在JS中合法,比如 ;;; 可解析为三个空语句(empty statement)

空语句可用于辅助产生语法合法的解析结果,如:

1

while(1);

如果没有末尾的分号,将会产生解析错误 ―― 条件循环后必须跟随一个语句

分号还会出现在 for 循环 for ( Expression ; Expression ; Expression ) Statement 中

最后,分号还会出现在 字符串 或 正则表达式中 ―― 表示分号本身

分号可以省略的场景

有些场景下分号可以省略,解析器在解析语句时会根据需要自动插入分号,大概流程可以这样理解:

书写省略 => 解析器解析时发现缺少时会无法正确解析 => 自动添加分号

so 需要明确能自动插入分号的场景,并明确不会自动插入分号且会引起解析错误的情况

规则1:当下一个 token (offending token) 和当前解析的 token (previous token) 无法组成合法语句,且满足以下一个或多个条件时,将会在 offending token 前插入一个分号:

  • offending token 和 previous token 被至少一个换行符分割(LineTerminator),且分号插入的作用不是被解析为 空语句 (empty statement)
  • offending token 是 }
  • previous token 是 ), 并且插入的分号将被解析为do-while语句的终止分号

还要考虑一种优先级更高的条件:如果插入的分号会被解析为一个空语句,或是 for 语句的头部两个分号之一,这时不会插入分号(除了 do-while 语句的终止分号外)

规则2:当解析到达源代码文件 (input stream) 的末尾时,将自动添加一个分号标识解析结束

规则3:符合 restricted production 语法的语句 ―― 比较难翻译,看不懂的可以直接看栗子,这种情况主要描述的是:不应该出现换行符的地方出现换行符导致插入分号引起原语句含义变化

同时满足以下条件,将在 offending token 前自动插入一个分号:

  • offending token 和 previous token 组成合语法的 restricted production 语句
  • offending token 出现于 restricted production 语句描述中的 [no LineTerminaator here] 部分 ( the token would be the first token for a terminal or nonterminal immediately following the annotation “[no LineTerminator here]” within the restricted production )
  • offending token 和 previous token 之间至少存在一个换行符 (LineTerminator)

其中 restricted production 包括且只有以下:

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

UpdateExpression[Yield, Await]:

  LeftHandSideExpression[?Yield, ?Await] [no LineTerminator here] ++

  LeftHandSideExpression[?Yield, ?Await] [no LineTerminator here] --

 

ContinueStatement[Yield, Await]:

  continue;

  continue [no LineTerminator here] LabelIdentifier[?Yield, ?Await];

 

BreakStatement[Yield, Await]:

  break;

  break  [no LineTerminator here]  LabelIdentifier[?Yield, ?Await];

 

ReturnStatement[Yield, Await]:

  return;

  return  [no LineTerminator here]  Expression  [+In, ?Yield, ?Await];

 

ThrowStatement[Yield, Await]:

  throw [no LineTerminator here] Expression [+In, ?Yield, ?Await];

 

ArrowFunction[In, Yield, Await]:

  ArrowParameters[?Yield, ?Await] [no LineTerminator here] => ConciseBody[?In]

 

YieldExpression[In, Await]:

  yield [no LineTerminator here] * AssignmentExpression[?In, +Yield, ?Await]

  yield [no LineTerminator here] AssignmentExpression[?In, +Yield, ?Await]

简单总结:

使用 a++ 语句时,变量和 ++ 必须在同一行,否则会在 ++ 前插入分号导致语义不同

return throw yield continue break 后如果紧跟着换行,将会自动添加分号

箭头函数的 => 之前不应该有换行符

栗子 & 可能不符合预期的情况

符合预期情况

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

// 相当于 42;"hello"

42

"hello"

 

// offending token 是 }

if(x){y()}

 

// previous token 是 ) 且插入分号是 do while 语句的结束

var a = 1

do {a++} while(a<100)

console.log(a)

 

//  不会解析成 b++ 因为 b和++之间存在换行符,会在 b 之后自动插入分号

a = b

++c

可能不符合预期的情况

1

2

3

4

5

const hey = 'hey'

const you = 'hey'

const heyYou = hey + ' ' + you

 

['h', 'e', 'y'].forEach((letter) => console.log(letter))

会收到错误 Uncaught TypeError: Cannot read property 'forEach' of undefined , 因为 you 和 ['h', 'e', 'y'] 的连接能命中合法语法,故它们之间不会自动插入分号 ―― 与预期不一致,JS尝试将代码解析为:

1

2

3

const hey = 'hey';

const you = 'hey';

const heyYou = hey + ' ' + you['h', 'e', 'y'].forEach((letter) => console.log(letter))

再看一种情况:

1

2

3

4

const a = 1

const b = 2

const c = a + b

(a + b).toString()

会引发 TypeError: b is not a function 报错,因为会被解释为:

1

2

3

const a = 1

const b = 2

const c = a + b(a + b).toString()

除了 do while 语句外,不会有插入分号作为空语句的其他情况,或作为 for 语句头部的两个必要分号 :

1

2

3

4

5

if (a > b)

else c = d

 

for (a; b

)

以上均不是合法的 JS 语句,并且会引起报错

阅读剩余部分

相关阅读 >>

javascript如何判断是否数字

javascript如何获取修改value

使用proxy实现双向绑定的方法介绍(代码)

详解javascript中的内存管理

javascript跳出方法有哪些

es6中generator函数的用法介绍

javascript有数据类型么

javascript创建对象的方法有哪些

影响页面加载时间的5个常见错误

javascript现继承的四种方式(代码示例)

更多相关阅读请进入《javascript》频道 >>




打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

评论

管理员已关闭评论功能...