zoukankan      html  css  js  c++  java
  • 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 )。

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

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

    在ASI的机制中有一类语句叫做restricted productions(不知道中文叫啥)。简单来说,就是组成这类语句的两个token当中不允许出现换行符 。如果在第一个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%的分号都是不必要的。

      

  • 相关阅读:
    索引初识
    python数据类型之 元祖、列表字典
    linux常用命令之网络命令
    linux命令之查找find &grep
    python数据类型之可hash,不可hash
    python面向对象之封装,多态与继承
    python之新式类与经典类
    python之random随机函数
    CSS3选择器(一)
    关于居中
  • 原文地址:https://www.cnblogs.com/zhangcybb/p/7018576.html
Copyright © 2011-2022 走看看