今天发现js自动分号补齐的坑,来看如下两段代码:

function Hello(){
return
{
name: ’JavaScript’
};
} alert(Hello()); //输出undefined

  

function Hello(){
return{
name: ’JavaScript’
};
} alert(Hello()); //输出 [object Object]

  略看代码,差不多,但是输出却不一样。仔细看看第一段代码return后面多了个换行。我们平时写后端代码也经常有会这样换行后花括号左对齐的写法。但是在js这里这样写却有不同的输出。这种机制叫分号自动补齐机制( auto semicolon insertion,简称ASI )。

  知乎上有大神关于这个机制的解释:

  链接:https://www.zhihu.com/question/21076930/answer/17135846

在ASI的机制中有一类语句叫做restricted productions(不知道中文叫啥)。简单来说,就是组成这类语句的两个token当中不允许出现换行符 \n。如果在第一个token后面遇到了换行符,则判断语句结束,插入分号。restricted productions包括:

  • return xxx (xxx是要返回的对象)
  • throw xxx(xxx是要抛出的错误对象)
  • break / continue xxx(xxx是循环的标签)
  • 作为后缀的 ++ / --

其中前几个关键词还是挺容易记的,最后一条的原因是需要区分以下情况:

a
++
b

因为++/--既可以作为前缀又可以作为后缀,在这样的情况下作为后缀解析会遇上换行符,所以只能作为b的前缀,自动插入分号后变成:

a; ++b;

回到原题,Douglas Crockford认为 { 应该写在行尾,是为了避免换行符导致return直接返回undefined。

篇外:关于分号 ------------------------------------------------------------------------------------------------

很多人觉得ASI坑太多了所以提倡永远手动加分号,这样就不用费心去研究ASI的规则了。但事实上,即使永远手动加分号,你依然会被restricted productions这条规则坑,因为它是在你不想要分号的地方给你插入分号。所以不管你喜不喜欢分号,都最好花点时间好好了解一下ASI的规则。而一旦你知道了ASI所有的坑,不写分号其实是很简单的。

ASI真正需要注意的坑只有两个,restricted productions是其一,另一个就是当下一行开头是 ( [ / 这三个字符之一的时候:

a = b
(function () { ... }())

会被解析成

a = b(function () {...}());

换言之,( ) 会被看做是在调用函数b。同理,[ ] 会被看做是在获取b的属性,而被斜杠坑的情况则要求更苛刻一些:

a = b
/Error/i.test(str) && doSomething()

第二行的写法本身比较少见,但也不是不可能。结果会被解析成:

a = b / Error / i.test(str) && doSomething();

斜杠被解析成了除号!

要躲开这个坑,其实真的挺简单,只要尽量别用这三个字符作为一行开头就行了。事实上遇到比较多的也只有括号开头。真的避不开的话,可以在行头手动加个分号:

a = b
;(function () { ... }())

额外的一点是在for循环声明里面的分号是永远不能省的,ASI不会在for循环声明中插分号,但一般正常人不会把for的声明分三行写吧...

每次我看到 “javascript分号坑很多,所以应该永远加分号” 这样的说法总是有些不屑的,因为永远加分号并不是避免错误的办法,搞懂ASI是怎么回事才是。只要理解了这里说的两个坑,javascript里99%的分号都是不必要的。

  

auto semicolon insertion 自动分号补齐的坑的更多相关文章

  1. 【微收藏】来自Twitter的自动文字补齐jQuery插件 - Typeahead.js

    没图没逼格 事发有因 该插件可以结合本地数据进行一些操作.推荐关注一下H5的几种数据存储的方式(localstorage与sessionstorage.IndexedDB.离线缓存manifest文件 ...

  2. jQuery实现Twitter的自动文字补齐特效

    上图效果可以使用jQuery插件Typeahead.js来实现,这款jQuery插件来自于Twitter的一个新的项目,支持远程和本地的数据集.比较有特色的地方在于你可以将数据集使用本地存储(loca ...

  3. CocoaPods 导入第三方库头文件自动补齐

    使用了一段时间CocoaPods来管理Objective-c的类库,方便了不少.但是有一个小问题,当我在xcode输入import关键字的时候,没有自动联想补齐代码的功能,需要手工敲全了文件名,难以适 ...

  4. CocoaPods导入第三方库头文件自动补齐

    使用了一段时间CocoaPods来管理Objective-c的类库,方便了不少.但是有一个小问题,当我在xcode输入import关键字的时候,没有自动联想补齐代码的功能,需要手工敲全了文件名,难以适 ...

  5. GBin1插件推荐之马可波罗(Marco Polo),jQuery的自动补齐插件 - Autocomplete Plugin

    让我们Google一下"jQuery autocomplete plugin"(jquery自动补齐插件).在过去的4年中,我已经Google了很多次这个组合了.然而结果并没有变化 ...

  6. Eclipse -- 自动补齐设置和其他用法

    1:自动补齐设置:最简单的修改方式是:Windows——>Preferences——>Java-->Editor-->Content Asist,在Auto activatio ...

  7. js获取系统时间时自动补齐日期带零

    最近在开发中发现有日期不规范的问题,正常规则应该是yy-mm-dd,而在输出时候却变成yy-mm-d,这是js的date()方法在作怪 解决思路是若在10号前,则自动给它补齐一个0,下面给出解决方法, ...

  8. 为Debian/Ubuntu的apt-get install添加自动补齐/完成功能

    Debian/Ubuntu的apt-get太常用了,不过偶尔可能也会碰到不太熟悉,想不起来的包的名称,除了去debian packages去查找,另外的方法就是给Debian/Ubuntu添加自动补齐 ...

  9. jquery.autocomplete自动补齐和自定义格式

    1.简单的下拉自动补齐,可以使用本地或远程数据源 <input name="autoTag" id="autoTag" /> var source ...

随机推荐

  1. laravel获取参数

    测试url如下 http://127.0.0.1:8888/testApp/public/testInput?aaa=1&bbb=2 测试代码 Route::get('/testInput', ...

  2. 快速接入PHP微信支付

    微信支付是微信开发中坑最多的一个功能,本文旨在帮助有开发基础的人快速接入微信支付,如果要详细了解微信支付,请看微信支付的开发文档. 再说把开发文档搬到这里来就没必要了.想要快速跑通微信支付的可以继续查 ...

  3. 构建Mogilefs分布式文件系统(配置篇)

    构建Mogilefs分布式文件系统:  当下互联网飞速发展,海量并发所产生的数据量以几何方式增长,随着信息链接方式日益多样化,数据存储的结构也发生了变化,在这样的压力下我们不得不重新审视大量数据的存储 ...

  4. bzoj2656 数列

    Description 小白和小蓝在一起上数学课,下课后老师留了一道作业,求下面这个数列的通项公式: A[0]=0 A[1]=1 A[2n]=A[n] A[2n+1]=A[n]+A[n+1] 小白作为 ...

  5. 关于 appium get_attribute --获取对应属性值 API说明

    1.获取 content-desc 的方法为 get_attribute("name") ,而且还不能保证返回的一定是 content-desc (content-desc 为空时 ...

  6. 1116 Come on! Let's C (20 分)

    1116 Come on! Let's C (20 分) "Let's C" is a popular and fun programming contest hosted by ...

  7. 牛客网暑期ACM多校训练营(第七场)J题(Sudoku Subrectangles)题解

    一.题意 给定一个高度为$n$,宽度为$m$的字母矩形(有大写和小写字母,共$52$种),问里面有多少个子矩形是“数独矩形”.数独矩形是指,该矩形内每一行内元素都不相同,每一列内元素也不相同. 二.思 ...

  8. Web API源码剖析之HttpServer

    Web API源码剖析之HttpServer 上一节我们讲述全局配置.本节将讲述全局配置的DefaultServer,它是一个HttpServer类型. 主要作用就是接受每一次请求,然后分发给消息处理 ...

  9. Deep Reinforcement Learning 基础知识

    Introduction 深度增强学习Deep Reinforcement Learning是将深度学习与增强学习结合起来从而实现从Perception感知到Action动作的端对端学习的一种全新的算 ...

  10. FIO read测试结果偏离

    工作中发现一个fio问题,测试组测试出来的数据read速度一个是17.0G/s,一个是13.2G/s.要知道我后台只有24块7.2k RPM的机械硬盘啊!怎么也不可能有这样的速度. 回家之后我模拟了实 ...