zoukankan      html  css  js  c++  java
  • JavaScript中(function(){…})(); 与 (function(){…}()); 这两种写法在意义上有什么区别?(转)

    这个问题可以从不同的角度来看,但从结果上来说,个人的意见是:他们是一样的

    首先,如果从AST(抽象语法树)的角度来看,这边我使用了uglify-js(https://github.com/mishoo/UglifyJS)来进行AST的生成,这个库应该在生成javascript的AST中算是比较流行的了,其结果如下:
    代码:(function() {}());
    结果:
    [
    "toplevel",
    [
    [
    "stat",
    [
    "call",
    [
    "function",
    null,
    [],
    []
    ],
    []
    ]
    ]
    ]
    ]


    代码:(function() {})();
    结果:
    [
    "toplevel",
    [
    [
    "stat",
    [
    "call",
    [
    "function",
    null,
    [],
    []
    ],
    []
    ]
    ]
    ]
    ]
    从结果而言,两者的AST是一模一样的,最终结果都是一次函数调用。因此,就解析器产生的结果论而言,两者是没有区别的。

    其次 ,从作用上看,前文已经说了,两者的作用都是创建一个函数并调用之。
    那么为什么要创建一个函数并立即调用呢,我想大多数是因为javascript的代码默认在全局环境下执行,在此声明的所有变量都会变成全局变量,这很容易导致全局对象的污染。因此我们不得不找一个办法来隔离这些变量,而函数正好会创建属于自己的作用域,因此创建一个匿名函数并立即调用(有称此为IIFE-Immediately Invoked Function Exprssion-立即调用的函数表达式)成为了一种几乎公认的方案。
    随后,又为什么要这么写呢?原因自然是在javascript中有2个语法都与function关键字有关,分别是:
    函数定义:function FunctionName(FormalParameterList) { FunctionBody }
    函数表达式:function [FunctionName](FormalParameterList) { FunctionBody }
    从语法的定义上看,这两者几乎是一模一样的(唯一的区别是函数表达式可以省略函数名称),那么就解释器而言,当遇到这个结构的语句时,判定为函数表达式还是函数定义呢?
    就javascript的语法而言,如果一条语句是以function关键字开始,那么这段会被判定为函数定义。而函数定义是不能被立即执行的,这无疑会导致语法的错误(SyntaxError),因此就必须有一个办法,使解析器可以将之识别为函数表达式。
    前面已经说到,解析器识别函数定义的条件是以function关键字开始,那么自然,只要在function关键字的前面有任何其他的元素,就会从函数定义转变为函数表达式,以下方法都是可以的,这个大家都知道:
    ~function() {}();
    !function() {}();
    void function() {}();

    但是这几个方法都有一个特点,就是看起来很别扭,所以现在为止,以括号包裹成了比较公认的方案。
    回到正题,括号包裹同样有2个方式:(function() {})();和(function(){}());
    他们的共通点是:都有括号。而括号在javascript中有2种作用:确立运算优先级,以及分组运算符(http://es5.github.com/#x11.1.6),从代码上看,显然没有进行数学或逻辑运算,因此我认为这里的括号属于分组运算符
    根据标准,分组运算符的作用是:
    Return the result of evaluating Expression. This may be of type Reference. 

    返回评估括号中的表达式的结果。结果可能是Reference类型。
    抛开像Reference类型这种词汇,这里的一个关键词应当是“ 评估 ”(对evaluate的翻译一直把握不好,姑且这么叫吧),但是关于分组运算符,又有一个很重要的下文:
    This algorithm does not apply GetValue to the result of evaluating Expression.

    这个算法不会对估算的结果使用GetValue。
    有很多专用的名词,看起来确实复杂,简而言之,使用括号运算符本身不会让括号中的代码立即执行,只有当括号包含的这个“分组”参与其他运算时,才会执行。因此,(function(){})()这个语句,其实是首先用分组运算符评估了一个函数表达式,随后参与“函数调用”。而(function(){}())这个语句,则是用分组运算符评估了一个函数调用,随后由于语句的结束而被执行。从语句上来说有细微的差距,当然就结果而言是一样的,最初的AST分析也可以证实这点,分组运算符在AST中完全没有体现出来。

    补充一点,分组运算符在AST中是完全被忽略的,例如以下结果:
    代码:var type = (typeof 2);
    语法树:
    [
    "toplevel",
    [
    [
    "var",
    [
    [
    "type",
    [
    "unary-prefix",
    "typeof",
    [
    "num",
    2
    ]
    ]
    ]
    ]
    ]
    ]
    ]

    可以看到依旧没有括号的位置,和var type = typeof 2;产生的AST是一模一样的。

    other: 

    (function(){…})(); 这种写法是因为JS中没有块级作用域的概念,所以可以用lambda函数来模仿块级作用域,这个的作用是定义并立即调用一个lambda函数,这个函数中定义的任何变量,都在执行结束时将被销毁,这样写还有个好处就是可以避免命名空间的污染。

    (function(){…}()); 这种应该算是模块模式的写法,是为单例创建私有变量和特权方法使单例得到增强。
  • 相关阅读:
    问题6-10
    7.19 1
    经济学人常见词汇清单
    英语广播原声听力100篇MP3及听力原文
    6.30.2018
    6.26
    6.26
    6.26
    6.25
    6.25
  • 原文地址:https://www.cnblogs.com/xiaohong/p/4065462.html
Copyright © 2011-2022 走看看