JS语法特性

733 阅读3分钟

这里有一份简洁的前端知识体系等待你查收,看看吧,会有惊喜哦~如果觉得不错,恳求star哈~


前言

本文将介绍JS的两种语法特性。


自动插入分号规则

自动插入分号规则非常简单,只有三条。

  1. 要有换行符,且下一个符号是不符合语法的,那么就尝试插入分号。
  2. 有换行符,且语法中规定此处不能有换行符,那么就自动插入分号。
  3. 源代码结束处,不能形成完整的脚本或者模块结构,那么就自动插入分号。

关于第一条,例子如下:

let a = 1
void function(a){
  console.log(a);
}(a);

在这个例子中,第一行的结尾处有换行符,接下来void关键字接在1之后是不合法的,这命中了我们的第一条规则,因此会在void前插入换行符。

关于第二条,例子如下:

var a = 1, b = 1, c = 1;
a
++
b
++
c

由于 ++ 之前不能有空格,于是,这里a的后面就要插入一个分号了。所以这段代码最终的结果,b和c都变成了2,而a还是1。

// 实际执行的代码如下:
var a = 1, b = 1, c = 1;
a;
++b;
++c;

到底什么情况下是不允许出现换行符?这就涉及到另一个语法规则:no LineTerminator here。


no LineTerminator here 规则

no LineTerminator here规则表示它所在的结构中的这一位置不能插入换行符。

自动插入分号规则的第二条:有换行符,且语法中规定此处不能有换行符,那么就自动插入分号。跟no LineTerminator here规则强相关,那么我们就找出JS语法定义中的这些规则。

前面不允许加换行符的有

  1. 后自增、后自减运算符前不能插入换行
  2. 箭头函数前,也不能插入换行

后面不允许加换行符的有

  1. 带标签的continue,不能在continue后插入换行
  2. 带标签的break,不能在break后插入换行
  3. return后不能插入换行
  4. 凡是async关键字,后面都不能插入换行
  5. yield之后,不能插入换行

中间不允许加换行符的有

  1. throw和Exception之间不能插入换行

不写分号需要注意的情况

1. 以括号开头的语句

(function(a){
  console.log(a);
})()/*这里没有被自动插入分号*/
(function(a){
  console.log(a);
})()

这段代码看似两个独立执行的函数表达式,但是其实第三组括号被理解为传参,导致抛出错误。


2. 以数组开头的语句

var a = [[]]/*这里没有被自动插入分号*/
[3, 2, 1, 0].forEach(e => console.log(e))

这段代码本意是一个变量a赋值,然后对一个数组执行forEach,但是因为没有自动插入分号,被理解为下标运算符和逗号表达式,甚至不会抛出错误,这对于代码排查问题是个噩梦。


3. 以正则表达式开头的语句

var x = 1, g = {test:()=>0}, b = 1/*这里没有被自动插入分号*/
/(a)/g.test("abc")
console.log(RegExp.$1)

这段代码本意是声明三个变量,然后测试一个字符串中是否含有字母a,但是因为没有自动插入分号,正则的第一个斜杠被理解成了除号,后面的意思就都变了。


4. 以Template开头的语句

var f = function(){
  return "";
}
var g = f/*这里没有被自动插入分号*/
`Template`.match(/(a)/);
console.log(RegExp.$1)

这段代码本意是声明函数f,然后赋值给g,再测试Template中是否含有字母a。但是因为没有自动插入分号,函数f被认为跟Template一体的,进而被莫名其妙地执行了一次。


总结

这篇文章中,我们讨论了要不要加分号的问题。

首先我们介绍了自动插入分号机制,又对 JS 语法中的no line terminator规则做了个整理,最后,我们挑选了几种情况,介绍了不写分号需要注意的一些常见的错误。