JavaScript上这两种类型的自执行函数的区别

时间:2011-12-04 18:57:13

标签: javascript

我总是使用以下自执行功能,以避免在JavaScript中将我的代码暴露给全局范围:

(function() { 
    //Code comes here
})();

我相信这也称为自动执行匿名函数。有时,我也看到下面的代码用于相同的目的:

(function(d){
    //Code comes here
})(document.documentElement);

我不确定这里有什么不同所以我问这个问题。

这两种类型的自执行函数在JavaScript上有什么区别(或差异)?

6 个答案:

答案 0 :(得分:8)

下面的代码演示了正在发生的事情。实际上,foobar变量不存在,并且函数是匿名的。

var foo = function() {}
foo();

var bar = function(d){}
bar(document.documentElement);

(function(d){})(d)方法称为闭包。它用于传递可能发生变化的变量值,例如循环。

看一个实际的例子:

for(var i=0; i<10; i++) {
    document.links[i].onclick = function(){
        alert(i); //Will always alert 9
    }
}

实施关闭后:

for(var i=0; i<10; i++) {
    (function(i){
        document.links[i].onclick = function(){
            alert(i); //Will alert 0, 1, ... 9
        }
    })(i);
}

答案 1 :(得分:3)

请记住,函数参数和变量在内心深处是相同的。

第二个例子(基本上)只是简写

(function(){
    var d = document.documentElement;
}());

因为它无需var=

此模式有一些常见用途:

  1. 创建词法范围的变量(在看到Rob的答案后才记得这个......)

    //this does not work because JS only has function scope.
    // The i is shared so all the onclicks log N instead of the correct values
    for(var i = 0; i< N; i++){
       elems[i].onclick = function(){ console.log(i); }
    }
    
    //Each iteration now gets its own i variable in its own function
    // so things work fine.
    for(var i=0; i<N; i++){
       (function(i){
           elems[i].onclick = function{ console.log(i); };
       }(i));
    }
    

    在这种情况下,直接传递参数允许我们以var i = i无法使用的方式在中重复使用相同的变量名称。此外,简洁是一个好处,因为这只是一个样板模式,我们不想主导它周围的重要代码。

  2. 它可以轻松转换一些旧代码,而无需过多考虑它

    (function($){
       //lots of code that expected $ to be a global...
    }(jQuery)) //and now we can seamlessly do $=jQuery instead.
    
  3. 未传递的参数设置为undefined。这很有用,因为通常undefined只是一个可以设置为不同值的全局变量(如果您正在编写需要使用任意第三方脚本工作的库,这一点非常重要)

    (function(undefined){
       //...
    }())
    

答案 2 :(得分:0)

第一个函数不带参数。第二个采用单个参数。在函数内部,参数为d。调用该函数时,d设置为document.documentElement

答案 3 :(得分:0)

看起来第二个代码的作者想要使用d作为在函数内编写document.documentElement的更短方法。

答案 4 :(得分:0)

使用带有参数的第二种形式的一个原因是,使您的代码与稍后在页面上加载的其他js代码(例如其他库或框架代码)隔离,这些代码可能会重新定义作为参数传入的变量。

一个常见的例子是,如果自执行匿名函数中的代码依赖于jQuery并且想要使用$变量。

其他js框架也定义了$ variable。如果您将函数编码为:

(function($){

    //Code comes here

})(jQuery);

然后你可以安全地使用$ for jQuery,即使你加载了一些定义$。的其他库。

我已经看到这个用于防守,人们在他们的块中传递他们需要的所有“全局”变量,例如窗口,文档,jQuery / $等。

比安慰更安全,特别是如果你使用了很多第三方小工具和插件。

<强>更新
正如其他人指出的那样,函数周围的括号集是一个闭包。在使用这种模式的情况下,很多时候它们并不是非常必要的(@Rob W给出了一个很好的例子,它们是必不可少的)但是说你有一个很长的函数体......外部括号说其他人读取代码该功能可能是自动执行的。

我看到这种模式的最佳解释是在Paul Irish的视频中:http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/从1:30左右开始

这个问题也有一些信息丰富的答案:How do you explain this structure in JavaScript?

答案 5 :(得分:0)

如果要将参数传递给自执行匿名函数,请使用第二个参数。当您想在函数中使用与全局范围内的其他名称相同的变量时,它可能会派上用场:

var a = "I'm outside the function scope",
    b = 13;
alert(a);
alert(b);
(function(a,b){
     // a is different from the initial a
     alert(a);
     // same goes for b
     alert(b);
})("I'm inside the function scope",Math.PI);

使用以下内容也很有用:

var a;
console.log(a === undefined); // true
undefined = true;
console.log(a === undefined); // false
(function(undefined){
    console.log(a === undefined); // true, no matter what value the variable "undefined" has assigned in the global scope
})();

尝试实施null object design pattern

如果您担心效率,最终可能会使用以下内容:

var a = 2;
(function(window){
    alert(a);
    // accessing a from the global scope gets translated 
    // to something like window.a, which is faster in this particular case
    // because we have the window object in the function scope
})(window);