包含函数的括号 - (function(){})()和`.call()`

Mel*_*991 0 javascript coffeescript

我已经写了一段时间javascript,最近一直在玩coffeescript.我注意到coffeescript以下列方式编译函数:

(function() {

}).call()
Run Code Online (Sandbox Code Playgroud)

我也注意到人们用这种方式写函数:

(function() {

})()
Run Code Online (Sandbox Code Playgroud)

据我所知,这些是自称的匿名函数.首先,拥有.call()和仅仅().call()一种更具语义的写作方式之间的区别是什么().

另外,为什么coffeescript将整个文件包装在匿名函数中,而通常不需要?这有什么表现或其他优势吗?应该何时使用这些自调用函数?

谢谢

Tod*_*tto 5

使用.call()将IIFE的上下文更改this为父范围的值.

第一个this浏览器环境中[object Window]的全局范围:

(function () {

    console.log(this);

})();
Run Code Online (Sandbox Code Playgroud)

第二个,将完全相同:

(function () {

    console.log(this);

}).call(this);
Run Code Online (Sandbox Code Playgroud)

区别在于ECMAScript 5中的strict mode第一个示例this将是未定义的:

(function () {

    'use strict';

    console.log(this); // undefined

})();
Run Code Online (Sandbox Code Playgroud)

但是,当使用严格模式 .call()时,这又是具有正确this上下文的全局范围:

(function () {

    'use strict';

    console.log(this);

}).call(this);
Run Code Online (Sandbox Code Playgroud)

这是一个显示这个的jsFiddle.主要区别在于normalIIFE失去了它的this上下文,一些CommonJS平台评估具体的文件this.

CoffeeScript这样做是为了确保您的代码与this放置它的作用域(父作用域)具有相同的上下文 - 因为函数通常不会this从周围的上下文继承它们的对象.

使用上面的模式,您应该将函数逻辑包装在那里,以避免将所有代码放在全局范围内并且具有变量/命名冲突,然后您可以创建诸如模块之类的东西并仅返回您的API需要,例如:

var Module = (function () {

    'use strict';

    return {
        someMethod: function () {
            // do something
        }
    }

})();

// call it:
Module.someMethod();
Run Code Online (Sandbox Code Playgroud)

每个函数都创建它自己的作用域,因此将代码块包装在其中将保护您的变量/函数名称不会相互冲突.我们还可以从这些闭包中访问"私有"方法:

var Module = (function () {

    'use strict';

    var _privateMethod = function () {};

    return {
        someMethod: function () {
            _privateMethod();
        }
    }

})();
Run Code Online (Sandbox Code Playgroud)

当我们不希望我们的用户也可以公开访问这些方法时,我们会这样做.