(function(){})()构造如何工作以及人们为什么使用它?

时间:2009-10-28 18:29:01

标签: javascript

(function() {})()及其jQuery特定的表兄(function($) {})(jQuery)一直在Javascript代码中弹出。

这些结构如何运作,以及它们解决了哪些问题?

赞赏的例子

15 个答案:

答案 0 :(得分:72)

随着JavaScript框架的日益普及,$符号被用于许多不同的场合。因此,为了减轻可能的冲突,您可以使用这些结构:

(function ($){
  // Your code using $ here.
})(jQuery);

具体来说,这是一个匿名函数声明,它将立即执行作为参数传递主jQuery对象。在该函数中,您可以使用$来引用该对象,而不必担心其他框架也在范围内。

答案 1 :(得分:40)

这是一种用于限制变量范围的技术;这是防止变量污染全局命名空间的唯一方法。

var bar = 1; // bar is now part of the global namespace
alert(bar);

(function () {
   var foo = 1; // foo has function scope
   alert(foo); 
   // code to be executed goes here
})();

答案 2 :(得分:19)

1)它定义了一个匿名函数并立即执行它。

2)通常这样做是为了不用不需要的代码污染全局命名空间。

3)你需要从中公开一些方法,内部声明的任何东西都是“私有的”,例如:

MyLib = (function(){
    // other private stuff here
    return {
        init: function(){
        }
    };

})();

或者,或者:

MyLib = {};
(function({
    MyLib.foo = function(){
    }
}));

关键是,有很多方法可以使用它,但结果保持不变。

答案 3 :(得分:9)

它只是一个立即调用的匿名函数。您可以先创建该函数然后调用它,然后获得相同的效果:

(function(){ ... })();

的工作原理为:

temp = function(){ ... };
temp();

您也可以对命名函数执行相同的操作:

function temp() { ... }
temp();

您调用jQuery特定的代码只是在您使用jQuery对象的意义上。它只是一个带参数的匿名函数,可以立即调用。

你可以分两步完成同样的事情,你可以用你喜欢的任何参数来做:

temp = function(answer){ ... };
temp(42);

这解决的问题是它为函数中的代码创建了一个闭包。您可以在其中声明变量而不会污染全局命名空间,从而降低使用一个脚本和另一个脚本时发生冲突的风险。

在jQuery的特定情况下,您在兼容模式下使用它,它不会将名称$声明为jQuery的别名。通过将jQuery对象发送到闭包并命名参数$,您仍然可以使用与没有兼容模式相同的语法。

答案 4 :(得分:7)

它解释了here您的第一个构造为变量提供了范围。

  

变量的作用域是javascript中的函数级别。这与您在C#或Java等语言中的习惯不同,其中变量的作用域为块。这意味着如果在循环或if语句中声明变量,它将可用于整个函数。

     

如果您发现自己需要在函数内显式扩展变量,可以使用匿名函数来执行此操作。您实际上可以创建一个匿名函数,然后立即执行它,并且内部的所有变量都将作用于匿名函数:

(function() {
  var myProperty = "hello world";
  alert(myProperty);
})();
alert(typeof(myProperty)); // undefined

答案 5 :(得分:6)

执行此操作的另一个原因是消除您正在使用的框架$运算符的任何混淆。例如,要强制执行jQuery,您可以执行以下操作:

;(function($){
   ... your jQuery code here...
})(jQuery);

通过传入$运算符作为参数并在jQuery上调用它,即使你加载了其他框架,函数中的$运算符也会被锁定为jQuery。

答案 6 :(得分:5)

此构造的另一个用途是“捕获”将在闭包中使用的局部变量的值。例如:

for (var i = 0; i < 3; i++) {
    $("#button"+i).click(function() {
        alert(i);
    });
}

以上代码将使所有三个按钮弹出“3”。另一方面:

for (var i = 0; i < 3; i++) {
    (function(i) {
        $("#button"+i).click(function() {
            alert(i);
        });
    })(i);
}

这将使三个按钮按预期弹出“0”,“1”和“2”。

这样做的原因是闭包保持对其封闭堆栈 frame 的引用,该堆栈保存其变量的当前值。如果这些变量在闭包执行之前发生变化,那么闭包只会看到最新的值,而不是创建闭包时的值。通过将闭包创建包装在另一个函数中,如上面的第二个示例所示,变量i的当前值保存在匿名函数的堆栈框架中。

答案 7 :(得分:4)

这被视为closure。这意味着包含的代码将在其自己的词法范围内运行。这意味着您可以定义新的变量和函数,它们不会与闭包之外的代码中使用的命名空间冲突。

var i = 0;
alert("The magic number is " + i);

(function() {
   var i = 99;
   alert("The magic number inside the closure is " + i);
})();

alert("The magic number is still " + i);

这将生成三个弹出窗口,证明闭包中的i不会改变同名的预先存在的变量:

  • 幻数为0
  • 封闭内部的幻数是99
  • 幻数仍为0

答案 8 :(得分:2)

它们经常用在jQuery插件中。正如jQuery Plugins Authoring Guide中所解释的,{ }内声明的所有变量都是私有的,外部不可见,这样可以更好地封装。

答案 9 :(得分:2)

正如其他人所说,他们都定义了立即调用的匿名函数。我通常将此JavaScript类声明包装在此结构中,以便为该类创建静态专用作用域。然后我可以放置常量数据,静态方法,事件处理程序或该范围内的任何其他内容,它只对类的实例可见:

// Declare a namespace object.
window.MyLibrary = {};

// Wrap class declaration to create a private static scope.
(function() {
  var incrementingID = 0;

  function somePrivateStaticMethod() {
    // ...
  }

  // Declare the MyObject class under the MyLibrary namespace.
  MyLibrary.MyObject = function() {
    this.id = incrementingID++;
  };

  // ...MyObject's prototype declaration goes here, etc...
  MyLibrary.MyObject.prototype = {
    memberMethod: function() {
      // Do some stuff
      // Maybe call a static private method!
      somePrivateStaticMethod();
    }
  };
})();

在此示例中,MyObject类已分配给MyLibrary命名空间,因此可以访问。 incrementingIDsomePrivateStaticMethod()不能在匿名函数范围之外直接访问。

答案 10 :(得分:2)

这基本上是 namespace 你的JavaScript代码。

例如,您可以在其中放置任何变量或函数,并且从外部来看,它们不存在于该范围内。因此,当您将所有内容封装在那里时,您不必担心冲突。

最后的()意味着自我调用。您还可以在那里添加一个参数,它将成为您的匿名函数的参数。我经常使用jQuery执行此操作,您可以看到原因......

(function($) {

    // Now I can use $, but it won't affect any other library like Prototype
})(jQuery);

Evan Trimboli涵盖了answer中的其他内容。

答案 11 :(得分:1)

这是一个自我调用的功能。有点像写作的简写

function DoSomeStuff($)
{
}

DoSomeStuff(jQuery);

答案 12 :(得分:1)

上面的代码正在做的是在第1行创建一个匿名函数,然后在第3行用0参数调用它。这有效地封装了该库中定义的所有函数和变量,因为所有函数只能在匿名函数内部访问。

这是一种很好的做法,其背后的原因是避免使用变量和函数污染全局命名空间,这可能会被整个站点中的其他Javascript破坏。

为了阐明函数的调用方式,请考虑一个简单的例子:

如果您包含这一行Javascript,它将自动调用而不显式调用它:

alert('hello');

所以,采取这个想法,并将其应用于这个例子:

(function() {
    alert('hello')
    //anything I define in here is scoped to this function only
}) (); //here, the anonymous function is invoked

最终结果类似,因为匿名函数的调用与前一个示例类似。

答案 13 :(得分:1)

因为已经采取 代码答案:)我会提出建议,观看一些John Resig视频 video 1 ,{ {3}} (jQuery的发明者和JavaScript的主人)。

视频中提供了一些非常好的见解和解答。

这就是我在看到你的问题时碰巧做的事情。

答案 14 :(得分:0)

function(){ // some code here }

是在javascript中定义匿名函数的方法。它们可以让你在另一个函数的上下文中执行函数(否则你可能没有这个函数)。