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中,我们现在可以通过let
和const
创buildvariables。 它们都是块范围的(不同于函数范围的var
)。
因此,我们现在可以写更多更简单的代码来确保variables的作用域不会泄露出所需的块,而不是使用IIFE的复杂构造。
{ let count = 10; }; console.log(count); // Reference Error: count is not defined
在这个例子中,我们使用let
来定义一个count
variables,使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
被赋值为{}
,所以结果是app
和window.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); })();
这不需要比这更复杂。