auto semicolon insertion 自动分号补齐的坑
今天发现js自动分号补齐的坑,来看如下两段代码:
function Hello(){
return
{
name: ’JavaScript’
};
}
alert(Hello());
//输出undefined
function Hello(){
return{
name: ’JavaScript’
};
}
alert(Hello());
//输出 [object Object]
略看代码,差不多,但是输出却不一样。仔细看看第一段代码return后面多了个换行。我们平时写后端代码也经常有会这样换行后花括号左对齐的写法。但是在js这里这样写却有不同的输出。这种机制叫分号自动补齐机制( auto semicolon insertion,简称ASI )。
知乎上有大神关于这个机制的解释:
在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 自动分号补齐的坑的更多相关文章
- 【微收藏】来自Twitter的自动文字补齐jQuery插件 - Typeahead.js
没图没逼格 事发有因 该插件可以结合本地数据进行一些操作.推荐关注一下H5的几种数据存储的方式(localstorage与sessionstorage.IndexedDB.离线缓存manifest文件 ...
- jQuery实现Twitter的自动文字补齐特效
上图效果可以使用jQuery插件Typeahead.js来实现,这款jQuery插件来自于Twitter的一个新的项目,支持远程和本地的数据集.比较有特色的地方在于你可以将数据集使用本地存储(loca ...
- CocoaPods 导入第三方库头文件自动补齐
使用了一段时间CocoaPods来管理Objective-c的类库,方便了不少.但是有一个小问题,当我在xcode输入import关键字的时候,没有自动联想补齐代码的功能,需要手工敲全了文件名,难以适 ...
- CocoaPods导入第三方库头文件自动补齐
使用了一段时间CocoaPods来管理Objective-c的类库,方便了不少.但是有一个小问题,当我在xcode输入import关键字的时候,没有自动联想补齐代码的功能,需要手工敲全了文件名,难以适 ...
- GBin1插件推荐之马可波罗(Marco Polo),jQuery的自动补齐插件 - Autocomplete Plugin
让我们Google一下"jQuery autocomplete plugin"(jquery自动补齐插件).在过去的4年中,我已经Google了很多次这个组合了.然而结果并没有变化 ...
- Eclipse -- 自动补齐设置和其他用法
1:自动补齐设置:最简单的修改方式是:Windows——>Preferences——>Java-->Editor-->Content Asist,在Auto activatio ...
- js获取系统时间时自动补齐日期带零
最近在开发中发现有日期不规范的问题,正常规则应该是yy-mm-dd,而在输出时候却变成yy-mm-d,这是js的date()方法在作怪 解决思路是若在10号前,则自动给它补齐一个0,下面给出解决方法, ...
- 为Debian/Ubuntu的apt-get install添加自动补齐/完成功能
Debian/Ubuntu的apt-get太常用了,不过偶尔可能也会碰到不太熟悉,想不起来的包的名称,除了去debian packages去查找,另外的方法就是给Debian/Ubuntu添加自动补齐 ...
- jquery.autocomplete自动补齐和自定义格式
1.简单的下拉自动补齐,可以使用本地或远程数据源 <input name="autoTag" id="autoTag" /> var source ...
随机推荐
- 【Spring学习笔记-MVC-1.0】Spring MVC架构介绍
作者:ssslinppp 1. 核心架构图 2. 核心架构的具体流程步骤 3. 具体的核心开发步骤 4. 常用注解 5. <mvc:annotation-driven>配置 6 ...
- sigar在Centos和Windows下使用java系统软硬件配置信息
背景 本来这个网上一大堆实在没什么想写的,但是好像大多数都是互相抄袭的,在centos根本上用不了,因此我整理下自己具体实现的步骤. 使用环境 sigar版本:hyperic-sigar-1.6.4 ...
- ApplicationEvent事件机制源码分析
<spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情> <服务网关zu ...
- Logstash之二:原理
一.Logstash 介绍 Logstash 是一款强大的数据处理工具,它可以实现数据传输,格式处理,格式化输出,还有强大的插件功能,常用于日志处理. 二.工作流程 Logstash 工作的三个阶段: ...
- Bootstrap:目录
ylbtech-Bootstrap:目录 1.返回顶部 1. https://getbootstrap.com/ 2. 2.返回顶部 1. http://www.runoob.com/bootstra ...
- vcenter修改用户密码的方法
https://192.168.x.x:9443登录,必须用administrator@vsphere.local登录,不能用root用户登录. 主页-系统设置- Single Sing-On-用户和 ...
- 使用oracle导出的dmp文件(包含表结构还是表数据?)
我们都知道oracle提供了一个exp程序,可以导出dmp文件,那么dmp文件中到底包含哪些东西呢? 1:有对象的信息吗?比如对象的权限? 2:有表空间信息吗? 3:有表结构吗? 4:有表的索引和触发 ...
- mysql互为主从
摘自:http://flash520.blog.163.com/blog/static/3441447520101029114016823/ A B 为两台MySQL服务器,均开启二进制日志,数据库版 ...
- 洛谷P1414 又是毕业季II
题目背景 “叮铃铃铃”,随着高考最后一科结考铃声的敲响,三年青春时光顿时凝固于此刻.毕业的欣喜怎敌那离别的不舍,憧憬着未来仍毋忘逝去的歌.1000多个日夜的欢笑和泪水,全凝聚在毕业晚会上,相信,这一定 ...
- 求m-n之间数字的和
unction sum(m,n){ var sum = 0; if(m>n){ for(var i=n; i<=m; i++ ...