JavaScript中的(function(){})()构造是什么?

我曾经知道这是什么意思,但我现在正在努力…

这基本上是说document.onload

 (function () { })(); 

这是一个立即调用函数expression式 ,简称IIFE 。 它在创build后立即执行。

它与任何事件的事件处理程序(如document.onload )无关。
第一对圆括号( function(){...} )把(在这种情况下是一个函数)内的代码转换成一个expression式,第二对圆括号(function(){...}) ()该评估expression式产生的函数。

当试图避免污染全局命名空间时,经常使用这种模式,因为在IIFE内使用的所有variables(如任何其他正常函数)在其范围之外是不可见的。
这就是为什么,也许你把这个构造与window.onload的事件处理器混淆了,因为它经常被这样使用:

 (function(){ // all your code here var foo = function() {}; window.onload = foo; // ... })(); // foo is unreachable here (it's undefined) 

Guffabuild议的更正 :

该函数在创build后立即执行,而不是在parsing之后执行。 在执行任何代码之前,整个脚本块都会被parsing。 此外,parsing代码并不意味着它被执行,例如,如果IIFE是在一个函数内,那么直到函数被调用才会被执行。

这只是一个匿名函数,在创build后立即执行。

就好像你把它分配给一个variables,并且在之后使用它,只是没有variables:

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

在jQuery中有一个类似的结构,你可能会想到:

 $(function(){ }); 

这是约束ready事件的简短forms:

 $(document).ready(function(){ }); 

立即调用的函数expression式(IIFE)立即调用函数。 这只是意味着函数在完成定义后立即执行。

三个更常见的措辞:

 // Crockford's preference - parens on the inside (function() { console.log('Welcome to the Internet. Please follow me.'); }()); //The OPs example, parentheses on the outside (function() { console.log('Welcome to the Internet. Please follow me.'); })(); //Using the exclamation mark operator //https://stackoverflow.com/a/5654929/1175496 !function() { console.log('Welcome to the Internet. Please follow me.'); }(); 

如果其回报价值没有特别的要求,那么我们可以这样写:

 !function(){}(); // => true ~function(){}(); // => -1 +function(){}(); // => NaN -function(){}(); // => NaN 

或者,它可以是:

 ~(function(){})(); void function(){}(); true && function(){ /* code */ }(); 15.0, function(){ /* code */ }(); 

你甚至可以写:

 new function(){ /* code */ } 31.new function(){ /* code */ }() //If no parameters, the last () is not required 

它声明了一个匿名函数,然后调用它:

 (function (local_arg) { // anonymous function console.log(local_arg); })(arg); 

这就是说马上执行。

所以如果我这样做:

 var val = (function(){ var a = 0; // in the scope of this function return function(x){ a += x; return a; }; })(); alert(val(10)); //10 alert(val(11)); //21 

小提琴: http : //jsfiddle.net/maniator/LqvpQ/


第二个例子:

 var val = (function(){ return 13 + 5; })(); alert(val); //18 

该构造被称为立即调用函数expression式(IIFE) ,意味着立即执行。 把它当作解释器到达该函数时自动调用的函数。

最常见的用例:

其最常见的用例之一是限制通过var创build的variables的范围。 通过var创build的variables有一个作用域限于一个函数,所以这个构造(这是某个代码的函数包装)将确保你的variables作用域不会泄漏出该函数。

在下面的例子中,在直接调用的函数外计数将不可用,即count范围不会泄漏出函数。 你应该得到一个Reference Error ,如果你试图在直接调用的函数之外访问它。

 (function () { var count = 10; })(); console.log(count); // Reference Error: count is not defined 

ES6替代品(推荐)

在ES6中,我们现在可以通过letconst创buildvariables。 它们都是块范围的(不同于函数范围的var )。

因此,我们现在可以写更多更简单的代码来确保variables的作用域不会泄露出所需的块,而不是使用IIFE的复杂构造。

 { let count = 10; }; console.log(count); // Reference Error: count is not defined 

在这个例子中,我们使用let来定义一个countvariables,使count限制在代码块中,我们使用大括号{...}

我叫它Curly Jail

不,这个构造只是为命名创build一个范围。 如果你把它分成几部分,你可以看到你有一个外部的

 (...)(); 

这是一个函数调用。 括号内有:

 function() {} 

这是一个匿名函数。 所有在构造内部用var声明的东西只会在同一个构造中可见,不会污染全局名称空间。

 (function () { })(); 

这被称为IIFE(立即调用函数expression式)。 着名的javascriptdevise模式之一,是现代模块模式的核心和灵魂。 顾名思义,它在创build后立即执行。 这种模式创build一个孤立的或私人的执行范围。

在使用词法作用域的ECMAScript 6之前的JavaScript,IIFE用于模拟块作用域。 (通过引入let和const关键字,可以使用ECMAScript 6块范围确定。) 有关词法作用域问题的参考

使用IIFE模拟块范围

使用IIFE的性能好处是能够传递常用的全局对象,比如窗口,文档等等。作为一个通过减less范围查找的参数(记住,Javascript在本地范围内查找属性,并链接到全局范围)。 因此,在本地范围内访问全局对象,缩短查找时间,如下所示。

 (function (globalObj) { //Access the globalObj })(window); 

这是一个自我调用的匿名函数

查看W3School对自我调用函数的解释 。

函数expression式可以做成“自我调用”。

自调用expression式被自动调用(启动),而不被调用。

如果expression式后跟(),函数expression式将自动执行。

你不能自调用一个函数声明。

这是自我调用的匿名函数。 它在被定义时执行。 这意味着这个函数被定义并在定义之后立即调用。

语法的解释是:第一个()括号内的函数是没有名字的函数,next (); 括号中可以理解它在被定义的时候被调用。 而且你可以在第二个括号中传递任何参数,这个参数将被放在第一个括号中的函数中。 看到这个例子:

 (function(obj){ // Do something with this obj })(object); 

在这里,你传递的'object'可以通过'obj'在函数中访问,就像你在函数签名中抓取它一样。

自我执行的匿名function。 一旦创build就执行。

一个简短而虚拟的例子,这是有用的是:

 function prepareList(el){ var list = (function(){ var l = []; for(var i = 0; i < 9; i++){ l.push(i); } return l; })(); return function (el){ for(var i = 0, l = list.length; i < l; i++){ if(list[i] == el) return list[i]; } return null; }; } var search = prepareList(); search(2); search(3); 

因此,不要每次创build一个列表,只创build一次(less开销)。

自执行函数通常用于封装上下文并避免名称混淆。 您在(function(){..})()中定义的任何variables都不是全局的。

代码

 var same_name = 1; var myVar = (function() { var same_name = 2; console.log(same_name); })(); console.log(same_name); 

产生这个输出:

 2 1 

通过使用这个语法,您可以避免与JavaScript代码中其他地方声明的全局variables相冲突。

还有一个用例是caching对象不是全局的备忘录:

 var calculate = (function() { var cache = {}; return function(a) { if (cache[a]) { return cache[a]; } else { //calulate heavy operation cache[a] = heavyOperation(a); return cache[a]; } } })(); 

IIFE(立即调用的函数expression式)是脚本加载和消失后立即执行的函数。

考虑下面的函数写在一个名为iife.js的文件中

 (function(){ console.log("Hello Stackoverflow!"); })(); 

上面的代码将会在您加载iife.js时执行,并将打印出' Hello Stackoverflow! '在开发者工具'控制台上。

有关详细说明,请参阅立即调用的函数expression式(IIFE)

这是一个自我调用的匿名函数 。 通常称为立即调用函数expression式(IIFE)。

立即调用的函数expression式(IIFE)是一个创build后立即执行的函数。 它与任何事件或asynchronous执行都没有关系。 您可以定义一个IIFE,如下所示:

 (function() { // all your code here // ... })(); 

第一对圆括号function(){…}将圆括号内的代码转换为expression式。第二对圆括号调用由expression式产生的函数。

一个IIFE也可以被描述为一个自我调用的匿名函数。 它最常见的用法是限制通过var创build的variables的范围或封装上下文以避免名称冲突。

我认为这两组括号有点混淆,但我看到了另外一个例子,他们使用了类似的东西,我希望这会帮助你更好地理解:

 var app = window.app || (window.app = {}); console.log(app); console.log(window.app); 

所以如果没有定义windows.app ,那么window.app = {}立即执行,所以在条件评估期间window.app被赋值为{} ,所以结果是appwindow.app现在变成{} ,所以控制台输出是:

 Object {} Object {} 

从这里开始:

 var b = 'bee'; console.log(b); // global 

把它放在一个function上,它不再是全球性的 – 你的主要目标。

 function a() { var b = 'bee'; console.log(b); } a.(); console.log(b); // ReferenceError: b is not defined -- *as desired* 

立即调用函数 – oops:

 function a() { var b = 'bee'; console.log(b); }(); // SyntaxError: Expected () to start arrow function, but got ';' instead of '=>' 

使用括号避免语法错误:

 (function a() { var b = 'bee'; console.log(b); })(); // OK now 

您可以忽略函数名称:

 (function () { // no name required var b = 'bee'; console.log(b); })(); 

这不需要比这更复杂。