什么是直接函数用于?

时间:2013-06-20 11:34:05

标签: javascript function

我已经在JS编程了一段时间,但我从未想过要使用立即函数,例如:

(function(){
    console.log('hello, I am an immediate function');
}())

如果我刚刚写下来会有什么不同:

console.log('hello, I am an immediate function');

?我无论如何都无法访问此功能(它没有分配到任何地方)。我认为(但我不确定)我可以在没有直接功能的情况下实现所有功能 - 那么为什么人们会使用它呢?

6 个答案:

答案 0 :(得分:4)

Immediately invoked function expressions用于创建namespaces。我不会准确解释为什么IIFE如此重要 - 本·阿尔曼在这方面做得非常好。不过,我会说IIFE最重要的用途之一是创建闭包。考虑:

var counter = (function () {
    var count = 0;

    return function () {
        return ++count;
    };
}());

console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

我们使用IIFE的原因是因为JavaScript没有块范围。因此,IIFE用于模拟块范围。 JavaScript 1.7引入了let关键字,允许您创建块范围变量。但是大多数实现都不支持let,因此我们仍然使用IIFE。

例如,可以使用let关键字重写上述程序,如下所示:

var counter;

{
    let count = 0;

    counter = function () {
        ++count;
    };
}

console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

另请注意,IIFE可以返回值。普通块不能这样做。因此,您需要手动将返回值分配给全局变量。

然而,大多数情况下,IIFE用于封装库的私有状态。创建一堆全局变量被认为是不好的做法。

有时它用于封装逻辑上相似的元素,因为我们喜欢将人物分组。它可能没有什么区别,但组织代码是好的。例如,考虑:

function Pet(name) {
    this.name = name;
}

Pet.prototype.feed = function (food) {
    console.log(this.name + " is eating " + food + ".");
};

而不是这样,只需将代码封装起来如下:

var Pet = (function () {
    function Pet(name) {
        this.name = name;
    }

    Pet.prototype.feed = function (food) {
        console.log(this.name + " is eating " + food + ".");
    };

    return Pet;
}());

哦,最重要的。 IIFE也用于解决Javascript infamous Loop issue?

答案 1 :(得分:4)

更新
我找到了this question,我在那里详细介绍了闭包,完成了一些小图,以阐明闭包和功能范围是如何使用的(以及它们如何帮助你)。

IIFE是函数对象,是在JS中创建真实范围的唯一方法。它们被用在了各处。你曾经使用过jQuery或其他一些lib吗?然后你使用了使用IIFE的代码。
曾经看过node.js?然后你可能会遇到一些名为“模块模式”的东西 如果您已经编写了自己的构造函数,那么您可能想知道如何在对象上使用某种私有属性。答案是IIFE一次又一次。

另外:DOM api不是世界上最快的东西。拥有一个包含硬编码document.getElementById调用的函数意味着,每次调用该函数时,都将遍历DOM。那不太理想。解决此问题的快速而简单的方法是:

var f = (function(domReference)
{
    var visible = !!(domReference.style.visibility === 'block')
    return function()
    {//has access to vars and arguments of outer function
        domReference.style.visibility = visible ? 'none' : 'block';
        visible = !visible;
    }
}(document.getElementById('foobar'));

但也许最好的,最常见的例子是循环中的超时/间隔:

for (var i=0;i<10;i++)
{
    setTimeout((function(currentI)
    {
        return function()
        {
            console.log(currentI);
            console.log(i);
        }
    }(i)), 1000);

此处,currentI将记录0,1,2 ......依此类推,而i始终记录10。超时回调的原因不是获得i值的副本,而是引用变量i。该变量可以根据需要更改其值,当调用超时回调时,它将记录上次分配的值i。在定义回调时,未分配值i

没有详细介绍,我提到了对象的私有属性。好吧,这里有一个例子可以帮助你弄清楚为什么IIFE和功能范围是至关重要的,以及JS的强大功能:

var MyConstructor = (function()
{
    return function(foo, bar)
    {
        var initState = Array.prototype.slice.apply(arguments, [0]);
        this.getInit = function()
        {
            return initState;
        };
        this.foo = foo;
        this.bar = bar;
    }
}());
(function(constant)
{
    var F = function(args)
    {
        return MyConstructor.apply(this, args);
    },
    checkVar = constant || 'default constant value';
    F.prototype = MyConstructor.prototype;
    MyConstructor.prototype.getConstant = function()
    {
        if (constant !== checkVar)
        {//bad example
            return checkVar;
        }
        return constant;
    };
    MyConstructor.prototype.regularMethod = function()
    {
        return this.foo;
    };
    MyConstructor.prototype.copyFromInitState = function()
    {
        return new F(this.getInit());
    };
}('Immutable value'));

玩得开心......:P

答案 2 :(得分:1)

开发人员使用立即函数声明私有作用域。例如......

(function($){
   $("div").html("example");
})(jQuery);

使用此代码,您不需要全局范围内的$变量,只需外部window.jQuery。当你想使用另一个库在window对象中使用的变量名时,它可以防止可能的冲突(例如,你可以使用window.$作为另一个提议,比如Prototype.js)。

答案 3 :(得分:1)

自调用函数用于防止全局变量冲突。例如:

(function($){
    //your code 
})(jQuery);

在上面的例子中,如果它在使用jQuery和Prototype.js的页面中,你可以安全地引用$ object并且知道它是jquery的$ object而不是prototype的$ object。

答案 4 :(得分:1)

人们使用它是因为它是javascript中最强大的功能之一。阅读并欢迎使用Javascript。 http://javascript.crockford.com/private.html

答案 5 :(得分:0)

人们使用它的原因是模拟私有范围。匿名函数体中定义的任何变量都将从外部作用域隐藏(通常它是window而垃圾window与临时变量是不好的主意。)