不为人知的JavaScript自动分号插入机制( ASI )

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: JavaScript拥有自由的精神, ASI就是此精神的表现形式之一, ASI是Automatic semicolon insertion 的缩写, 在许多语句后面可以省略分号, 当然很多小白还没有发现这一点... ASI的引入方便了开发者的同时也带来了很多坑........ 本文介绍了自动插入分号机制在return语句中的例子,以及在es5标准下的相应规则。



JavaScript拥有自由的精神, ASI就是此精神的表现形式之一, ASI是 Automatic semicolon insertion  的缩写, 在许多语句后面可以省略分号, 当然很多小白还没有发现这一点...首先分号是必不可少的, 因为回车符号在词法分析阶段就被全部杀掉了(特殊作用域除外),所以有了ASI有些人会认为回车符也是分隔符,其实回车符就是空白符,没有任何意义....
 ASI的引入方便了开发者的同时也带来了很多坑........   本文介绍了自动插入分号机制在return语句中的例子,以及在es5标准下的相应规则。

楔子

之前一直写C,写了一段时间JavaScript之后一直很很好奇一个东西。在C和Java等语言里面,大括号的使用一般都是类似这样的

int main(args[])
{
    return 0;
}
  • 1
  • 2
  • 3
  • 4

而到JavaScript里面则是这样写

function main(args){
    alert("hello");
    return 0;
}
  • 1
  • 2
  • 3
  • 4

起始的大括号不独占一行了,觉得很疑惑,查了一些资料才知道,这是和JavaScript一个自动修复机制有关系,它总是希望通过自动插入分号来修正有缺损的程序,虽然我不知道这有什么用。

自动插入分号机制

在《JavaScript语言精粹》这本书里,这个机制被划入到了JavaScript的毒瘤里面,与之并列的前面的全局变量。

有些时候,不合时宜地插入分号,会在例如return语句里面导致严重的后果。 
如果一个return语句要正确返回一个值,这个值的表达式的开始部分必须和return位于同一行。

我们来看下面这个例子

return
{
    status:true;
}
  • 1
  • 2
  • 3
  • 4

看起来这是要返回一个包含对象,但是万恶的自动插入分号处理后,返回值变成了undefined,而且不会报任何的错误和警告。 
如果我们把大括号这样处理的话就能避免这个问题

return{
    status:true;
};
  • 1
  • 2
  • 3

自动插入分号的详细规则

在es5标准中定义了自动分号插入规则,包括以下三个基本规则加上两个前置条件。

前置条件

1.如果插入分号后解析结果是空语句,那么不会自动插入分号。 
例子:

if(i>j)
else k=l
  • 1
  • 2

这种情况下,if后面else前面是被解析为空语句,所以不加分号 
2.如果插入分号后,它会成为for语句头部的两个分号之一,那么也不会插入分号 
例如:

for(a;b
)
  • 1
  • 2

这种情况下,虽然分行了,但是不会被插入分号。

基本规则

从左向右解析程序的时候,当遇到一个不符合任何语法产生式的token也就是违规标记的时候,那么只要满足下列条件之一,就会在哪个标记之前自动插入一个分号 
1、前一个标记和这个违规标记之前至少存在一个行终止符 
2、违规的标记是 }

举个栗子

{1
    2}3
{1
    ;2;}3
  • 1
  • 2
  • 3
  • 4

在第一行和第二行的1、2不符合任何产生式,且它们之间有一个行终止符,所以会在数字2之前加分号,在第二行2后面也需要加一个分号,因为后面的违规标记是一个}

左到右解析程序,tokens 输入流已经结束,当解析器无法将输入 token 流解析成单个完整 ECMAScript 程序 ,那么就在输入流的结束位置自动插入分号。

对于受限产生式,也就是下面的5个,我们把产生式 后面的 token 叫做受限 token,如果在 token 和 受限 token 间存在了至少一个行终止符,那么会在受限 token 前自动加上 token。

受限的产生式只限如下5个:

后缀表达式continue语句break语句return语句throw语句

如何预防这个毒瘤

1、后缀运算符 ++ 或 -- 和它的操作数应该出现在同一行。 
2、returnthrow语句的表达式开始位置应该和 return或 throw token 同一行。 
3、break或 continue 语句的标示符应该和 break 或continuetoken 同一行。

最重要的还是多加分号

来自leviscar的小贴士 
为啥只执行函数前面要加分号? 
例如我之前看到的zepto.js的源码开头

;(function(undefined) {
  if (String.prototype.trim === undefined) // fix for iOS 3.2
  String.prototype.trim = function() {
    return this.replace(/^\s+|\s+$/g, '')
  }
  • 1
  • 2
  • 3
  • 4
  • 5

主要是应对代码合并压缩时,由于缺少分号;带来的错误。知道了上面的规则,在 ( 开头的行前加分号就可以避免错误了。

目录
相关文章
|
1月前
|
JavaScript 前端开发 算法
js 内存回收机制
【8月更文挑战第23天】js 内存回收机制
32 3
|
1月前
|
存储 JavaScript 前端开发
学习JavaScript 内存机制
【8月更文挑战第23天】学习JavaScript 内存机制
25 3
|
27天前
|
JavaScript 中间件 开发者
深入浅出Node.js中间件机制
【8月更文挑战第31天】本文将带你领略Node.js中间件的奥秘,通过直观的案例分析,揭示其背后的设计哲学。你将学会如何运用中间件构建强大而灵活的后端应用,以及在面对复杂业务逻辑时如何保持代码的清晰与高效。
|
27天前
|
设计模式 JavaScript 中间件
深入浅出Node.js中间件机制
【8月更文挑战第31天】在Node.js的世界里,中间件如同魔法般存在,它让复杂的请求处理变得井然有序。本文将带你领略中间件的奥秘,从原理到实战,一步步揭开它的神秘面纱。你将学会如何运用中间件来构建强大而灵活的后端应用,就像拼乐高一样有趣。
|
3月前
|
设计模式 JavaScript 前端开发
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
JavaScript的继承机制基于原型链,它定义了对象属性和方法的查找规则。每个对象都有一个原型,通过原型链,对象能访问到构造函数原型上的方法。例如`Animal.prototype`上的`speak`方法可被`Animal`实例访问。原型链的尽头是`Object.prototype`,其`[[Prototype]]`为`null`。继承方式包括原型链继承(通过`Object.create`)、构造函数继承(使用`call`或`apply`)和组合继承(结合两者)。ES6的`class`语法是语法糖,但底层仍基于原型。继承选择应根据需求,理解原型链原理对JavaScript面向对象编程至关重要
85 7
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
|
2月前
|
JavaScript 前端开发 API
js 运行机制(含异步机制、同步任务、异步任务、宏任务、微任务、Event Loop)
js 运行机制(含异步机制、同步任务、异步任务、宏任务、微任务、Event Loop)
31 0
|
4月前
|
缓存 移动开发 JavaScript
WKWebView对网页和js,css,png等资源文件的缓存机制及如何刷新缓存
WKWebView对网页和js,css,png等资源文件的缓存机制及如何刷新缓存
168 1
|
3月前
|
JavaScript 前端开发
深入解析JavaScript中的面向对象编程,包括对象的基本概念、创建对象的方法、继承机制以及面向对象编程的优势
【6月更文挑战第12天】本文探讨JavaScript中的面向对象编程,解释了对象的基本概念,如属性和方法,以及基于原型的结构。介绍了创建对象的四种方法:字面量、构造函数、Object.create()和ES6的class关键字。还阐述了继承机制,包括原型链和ES6的class继承,并强调了面向对象编程的代码复用和模块化优势。
43 0
|
4月前
|
开发框架 JavaScript 前端开发
JavaScript的事件循环机制是其非阻塞I/O的关键
【5月更文挑战第13天】JavaScript的事件循环机制是其非阻塞I/O的关键,由调用栈、事件队列和Web APIs构成。当异步操作完成,回调函数进入事件队列,待调用栈空时,事件循环取队列中的任务执行。在游戏开发中,事件循环驱动游戏循环更新,包括输入处理、游戏逻辑更新和渲染。示例代码展示了如何模拟游戏循环,实际开发中则常使用游戏框架进行抽象处理。
74 4