这种自调用匿名函数变体背后的原因

Posted

技术标签:

【中文标题】这种自调用匿名函数变体背后的原因【英文标题】:Reason behind this self invoking anonymous function variant 【发布时间】:2011-09-11 08:45:14 【问题描述】:

在 github 上查看 code 时,我发现了以下内容:

(function() 

).call(this);

这显然是一个自调用匿名函数。但是为什么会这样写呢?我习惯于看到规范变体(function() )()

.call(this) 用于自调用匿名函数有什么特别的优势吗?


编辑:看起来一些 commonjs 环境将 this 设置为模块顶层的非全局值。哪些,以及他们将this 设置为您可能想要保留的内容?

【问题讨论】:

***.com/questions/36636/what-is-a-closure的可能重复 @Rob 我不认为这是 Sean 在这个问题中要问的问题。 啊,找到了——绝对不是重复的问题,但答案类似:***.com/questions/5211638/… 哦,很好的链接@Matt。我可以看到,如果函数是嵌套的,这很有意义。 ***.com/questions/4542942/… 对此答案的评论说,一些 commonjs 环境将 this 设置为模块顶层的非全局变量。这可以解释为什么您可能需要保留 this 【参考方案1】:

默认情况下,调用(function()/*...*/)() 之类的函数会将函数中的this 的值设置为window(在浏览器中),而不管this 的值可能在封闭上下文中,其中函数已创建。

使用call 允许您手动将this 的值设置为您想要的任何值。在这种情况下,它将其设置为 this 在封闭上下文中的任何值。

举个例子:

var obj = 
    foo:'bar'
;

(function() 
    alert( this.foo ); // "bar"
).call( obj );

http://jsfiddle.net/LWFAp/

您可以看到我们能够手动将this 的值设置为obj 变量引用的对象。

【讨论】:

他的问题是在末尾添加this 的作用,而不是添加自定义对象的作用。 @Startec:没有区别。他们会做同样的事情。他只是传递了一个不同的对象,因此他可以通过函数内部的this 显示该对象的属性可用。 @sixfingeredman 对,这表明您可以通过在右括号中传入一个对象来设置 this 的值。但是,问题是,当您传入this 对象时会发生什么,而不是您已实例化的某个对象。换句话说,如果传入this 只是在封闭函数this 中生成this 的值,那为什么还要传入呢? @Startec:我明白你在说什么。由于它们实际上是相同的(除非在严格模式下),那有什么意义呢。虽然这个理由是基于 IIFE 的全球执行,但这个细节似乎稍后才添加到问题中。 有 ES2015 的方法吗?【参考方案2】:

.call(this)(实际上只是(),直到我改变它)确保您的***this通过严格模式、--bare选项和/或运行环境(***this没有'不指向全局对象)。

【讨论】:

这些都没有任何意义。 啊——().call(this) 在严格模式下是不同的。现在一切都说得通了。 .call(this) 为函数提供相同的上下文是严格模式和宽松模式。 @matyr 您能否通过有关 () 和 .call(this) 的描述或链接进一步解释它们在严格模式下的实际含义?我无法理解严格模式位。 在宽松模式下,如果你调用一个没有对象的函数,this 被设置为window。在严格模式下,this 设置为 undefined。使用.call(this)this(函数内部)显式设置为this(函数外部),从而确保它保持为window,无论您处于严格模式还是宽松模式。 谢谢,@SeanMcMillan。我其实明白你写的。我相信您的解释比答案要好得多。【参考方案3】:

通过使用:

> (function() 
>   ...
> ).call(this);`

然后将代码范围内的this(可能是全局对象)设置为函数的this对象。据我所知,它相当于:

(function(global) 
  // global references the object passed in as *this*
  // probably the global object
)(this);

在浏览器中,window 通常是(或表现得好像是)全局对象的别名。

【讨论】:

第一个肯定不等于第二个。 它提供对外部执行上下文的 this 的引用,并将其存储为名为 global 的局部变量,而不是 this。所以它是等价的,它只是将引用分配给本地激活/变量对象的不同属性。【参考方案4】:
C=
    descript: "I'm C!<br>",
    F: function() 
        //set this to the caller context's 'this'
        (function() 
            document.write(this.descript);
        ).call(this);

        //set this to 'window' or 'undefined' depend the mode
        (function() 
            document.write(this.descript);
        )();

        //member function's 'this' is the object self
        document.write(this.descript);
    


window.descript="I'm window!<br>";

C.F();

(function() ).call(this); 可以将匿名的this 设置为调用者上下文this,上面是C.(function() )();this 设置为windowundefined 取决于模式。

【讨论】:

【参考方案5】:

自调用函数对于在加载脚本时立即执行其内容很有用。这便于初始化全局范围元素。

【讨论】:

以上是关于这种自调用匿名函数变体背后的原因的主要内容,如果未能解决你的问题,请参考以下文章

自调用匿名函数(匿名闭包)解析与调用

自调用匿名函数

自调用匿名函数

(二十)python 3 匿名函数

(十六)golang--匿名函数

JS函数 -- 功能,语法,返回值,匿名函数,自调用匿名函数,全局变量与局部变量,arguments的使用