我曾经知道这意味着什么,但我现在正在努力......
这基本上是在说document.onload
吗?
(function () {
})();
答案 0 :(得分:769)
这是Immediately-Invoked Function Expression或简称IIFE。它在创建后立即执行。
它与任何事件(例如document.onload
)的任何事件处理程序无关
考虑第一对括号中的部分:(function(){})();
....它是一个常规函数表达式。然后查看最后一对(function(){})();
,这通常会添加到表达式中以调用函数;在这种情况下,我们先前的表达。
在尝试避免污染全局命名空间时经常使用此模式,因为IIFE内部使用的所有变量(与任何其他普通函数一样)在其范围之外是不可见的。
这就是为什么,您可能会将此构造与window.onload
的事件处理程序混淆,因为它通常用作:
(function(){
// all your code here
var foo = function() {};
window.onload = foo;
// ...
})();
// foo is unreachable here (it’s undefined)
Guffa建议的更正
该函数在创建后立即执行,而不是在解析之后执行。在执行任何代码之前解析整个脚本块。此外,解析代码并不会自动意味着它已被执行,如果例如IIFE在函数内部,那么在调用该函数之前它将不会被执行。
<强>更新强> 由于这是一个非常受欢迎的话题,值得一提的是,IIFE也可以用ES6's arrow function编写(如Gajus已指出in a comment):
((foo) => foo)('foo value')
答案 1 :(得分:104)
它只是一个在创建后立即执行的匿名函数。
就像你将它分配给一个变量,并在之后使用它,只是没有变量:
var f = function () {
};
f();
在jQuery中,您可能会想到一个类似的构造:
$(function(){
});
这是约束ready
事件的简短形式:
$(document).ready(function(){
});
答案 2 :(得分:45)
立即调用的函数表达式(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
答案 3 :(得分:31)
它声明了一个匿名函数,然后调用它:
(function (local_arg) {
// anonymous function
console.log(local_arg);
})(arg);
答案 4 :(得分:26)
这就是说立即执行。
所以,如果我这样做:
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
答案 5 :(得分:20)
该构造称为立即调用函数表达式(IIFE),这意味着它立即执行。可以把它当作一个在解释器达到该功能时自动调用的函数。
最常见的用例:
其最常见的用例之一是限制通过var
生成的变量的范围。通过var
创建的变量的范围仅限于函数,因此这个构造(它是某些代码的函数包装器)将确保您的变量范围不会泄漏出该函数。
在下面的示例中,count不会在紧接调用的函数之外可用,即count
的范围不会泄漏出函数。如果你试图在立即调用的函数之外访问它,你应该得到Reference Error
。
(function () {
var count = 10;
})();
console.log(count); // Reference Error: count is not defined
ES6替代方案(推荐)
在ES6中,我们现在可以通过let
和const
创建变量。它们都是块范围的(与函数作用域的var
不同)。
因此,不是在上面提到的用例中使用IIFE的复杂构造,现在可以编写更多,更简单的代码,以确保变量的作用域不会泄漏到您想要的块之外。
{
let count = 10;
};
console.log(count); // Reference Error: count is not defined
在此示例中,我们使用let
定义count
变量,使count
仅限于代码块,我们使用大括号{...}
创建。
我称之为Curly Jail
。
答案 6 :(得分:13)
(function () {
})();
这称为IIFE(立即调用函数表达式)。其中一个着名的javascript设计模式,它是现代模块模式的核心和灵魂。顾名思义,它在创建后立即执行。此模式创建一个独立或私有的执行范围。
使用词法作用域的ECMAScript 6之前的JavaScript,IIFE用于模拟块作用域。 (通过引入let和const关键字,可以使用ECMAScript 6块作用域。) Reference for issue with lexical scoping
Simulate block scoping with IIFE
使用IIFE的性能优势是能够传递常用的全局对象,如窗口,文档等。作为一个参数,通过减少范围查找。(记住Javascript查找本地范围内的属性,然后链接到全局范围)。因此,访问本地范围内的全局对象,减少查找时间,如下所示。
(function (globalObj) {
//Access the globalObj
})(window);
答案 7 :(得分:11)
不,这个构造只是为命名创建了一个范围。如果你打破它的部分你可以看到你有一个外部
(...)();
这是一个函数调用。在括号内你有:
function() {}
这是一个匿名函数。在构造中使用 var 声明的所有内容只能在同一个构造内部显示,并且不会污染全局命名空间。
答案 8 :(得分:9)
这是Javascript中立即调用的函数表达式:
要理解JS中的IIFE,让我们分解它:
a = 10 output = 10 (1+3) output = 4
// Function Expression var greet = function(name){ return 'Namaste' + ' ' + name; } greet('Santosh');
函数表达式的工作原理:
- 当JS引擎第一次运行时(执行上下文 - 创建阶段),此函数(在=上面的右侧)不会被执行或存储在内存中。变量问候&#39;已分配&#39;未定义&#39; JS引擎的价值。
- 在执行期间(执行上下文 - 执行阶段),功能对象即时创建(尚未执行),被分配给&#39;问候&#39;变量,可以使用&#39; greet(&#39; somename&#39;)&#39;来调用它。
第3。立即调用功能表达式
示例:
// IIFE
var greeting = function(name) {
return 'Namaste' + ' ' + name;
}('Santosh')
console.log(greeting) // Namaste Santosh.
IIFE如何运作:
- 注意&#39;()&#39;函数声明后立即。每个功能对象都有一个&#39; CODE&#39;附属于它的财产,可以赎回。我们可以使用&#39;()&#39;来调用它(或调用它)。括号。
- 所以这里,在执行期间(执行上下文 - 执行阶段),创建函数对象并同时执行
- 所以现在,greeting变量不是拥有funtion对象,而是返回值(字符串)
JS中IIFE的典型用例:
以下IIFE模式非常常用。
// IIFE
// Spelling of Function was not correct , result into error
(function (name) {
var greeting = 'Namaste';
console.log(greeting + ' ' + name);
})('Santosh');
因此,此功能会同时创建并执行(IIFE)。
IIFE的重要用例:
IIFE保证我们的代码安全。
- 作为一个函数的IIFE具有自己的执行上下文,这意味着在其中创建的所有变量都是该函数的本地变量,并且不与全局执行上下文共享。
假设我在我的应用程序中使用了另一个JS文件(test1.js)和iife.js(见下文)。
// test1.js
var greeting = 'Hello';
// iife.js
// Spelling of Function was not correct , result into error
(function (name) {
var greeting = 'Namaste';
console.log(greeting + ' ' + name);
})('Santosh');
console.log(greeting) // No collision happens here. It prints 'Hello'.
因此,IIFE帮助我们编写安全代码,使我们不会无意中与全局对象发生冲突。
答案 9 :(得分:6)
这是一个自我调用的匿名函数。
查看W3Schools explanation of a self-invoking function。
函数表达式可以“自我调用”。
自动调用(启动)自调用表达式,而不是 被召唤。
如果表达式是,函数表达式将自动执行 接着是()。
您无法自行调用函数声明。
答案 10 :(得分:5)
这是自我调用的匿名函数。它在定义时执行。这意味着定义了这个函数,并在定义后立即调用它。
语法的解释是:第一个()
括号内的函数是没有名称的函数,通过下一个();
括号,你可以理解它在它被调用时被调用被定义为。并且您可以在第二个()
括号中传递任何参数,这些参数将在第一个括号中的函数中获取。见这个例子:
(function(obj){
// Do something with this obj
})(object);
这里的对象&#39;当你在函数签名中抓取它时,你正在传递的函数可以在函数中访问。
答案 11 :(得分:3)
从这里开始:
var b = 'bee';
console.log(b); // global
将它放在一个函数中,不再是全局 - 这是您的主要目标。
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);
})();
它不需要比这更复杂。
答案 12 :(得分:2)
自动执行匿名功能。它会在创建后立即执行。
一个有用的简短虚拟示例是:
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);
因此,不是每次都创建一个列表,而是只创建一次(减少开销)。
答案 13 :(得分:2)
自执行函数通常用于封装上下文并避免名称共谋。您在(function(){..})()中定义的任何变量都不是全局变量。
代码
var same_name = 1;
var myVar = (function() {
var same_name = 2;
console.log(same_name);
})();
console.log(same_name);
生成此输出:
2
1
通过使用此语法,您可以避免与JavaScript代码中其他地方声明的全局变量发生冲突。
答案 14 :(得分:2)
它是一个函数表达式,代表立即调用函数表达式(IIFE)。 IIFE只是创建后立即执行的功能。因此,在必须等待调用该函数执行该函数的情况下,会立即执行IIFE。让我们以示例的方式构造IIFE。假设我们有一个add函数,该函数将两个整数作为args并返回总和 让我们将添加功能添加到IIFE中,
第1步:定义功能
function add (a, b){
return a+b;
}
add(5,5);
Step2:通过将整个函数声明包装在括号中来调用函数
(function add (a, b){
return a+b;
})
//add(5,5);
第3步:要立即调用该函数,只需从调用中删除“添加”文本即可。
(function add (a, b){
return a+b;
})(5,5);
使用IFFE的主要原因是为了在函数中保留私有范围。在您的JavaScript代码中,您要确保没有覆盖任何全局变量。有时您可能会意外地定义一个覆盖全局变量的变量。让我们以身作则。假设我们有一个名为iffe.html的html文件,body标记内的代码是-
<body>
<div id = 'demo'></div>
<script>
document.getElementById("demo").innerHTML = "Hello JavaScript!";
</script>
</body>
好吧,上面的代码将毫无疑问地执行,现在假定您意外或故意清除了一个名为document的变量。
<body>
<div id = 'demo'></div>
<script>
document.getElementById("demo").innerHTML = "Hello JavaScript!";
const document = "hi there";
console.log(document);
</script>
</body>
您将遇到 SyntaxError (语法错误):重新声明不可配置的全局属性文档。
但是,如果您希望清除变量名documet,则可以使用IFFE来实现。
<body>
<div id = 'demo'></div>
<script>
(function(){
const document = "hi there";
this.document.getElementById("demo").innerHTML = "Hello JavaScript!";
console.log(document);
})();
document.getElementById("demo").innerHTML = "Hello JavaScript!";
</script>
</body>
输出:
让我们再举一个例子,假设我们有一个像波纹管这样的计算器对象-
<body>
<script>
var calculator = {
add:function(a,b){
return a+b;
},
mul:function(a,b){
return a*b;
}
}
console.log(calculator.add(5,10));
</script>
</body>
好吧,它的工作就像一种魅力,如果我们不小心重新分配了计算器对象的值,该怎么办。
<body>
<script>
var calculator = {
add:function(a,b){
return a+b;
},
mul:function(a,b){
return a*b;
}
}
console.log(calculator.add(5,10));
calculator = "scientific calculator";
console.log(calculator.mul(5,5));
</script>
</body>
是的,您最终会遇到TypeError:Calculator.mul不是iffe.html函数
但是在IFFE的帮助下,我们可以创建一个私有范围,在其中我们可以创建另一个变量名计算器并使用它;
<body>
<script>
var calculator = {
add:function(a,b){
return a+b;
},
mul:function(a,b){
return a*b;
}
}
var cal = (function(){
var calculator = {
sub:function(a,b){
return a-b;
},
div:function(a,b){
return a/b;
}
}
console.log(this.calculator.mul(5,10));
console.log(calculator.sub(10,5));
return calculator;
})();
console.log(calculator.add(5,10));
console.log(cal.div(10,5));
</script>
</body>
答案 15 :(得分:1)
IIFE(立即调用函数表达式)是一个在脚本加载和消失后立即执行的函数。
考虑下面写在名为iife.js
的文件中的函数(function(){
console.log("Hello Stackoverflow!");
})();
上面的代码将在您加载iife.js后立即执行,并将打印&#39; Hello Stackoverflow!&#39;关于开发者工具&#39;安慰。
答案 16 :(得分:1)
另一个用例是memoization,其中缓存对象不是全局的:
var calculate = (function() {
var cache = {};
return function(a) {
if (cache[a]) {
return cache[a];
} else {
// Calculate heavy operation
cache[a] = heavyOperation(a);
return cache[a];
}
}
})();
答案 17 :(得分:0)
立即调用的函数表达式(IIFE)是一旦创建就执行的函数。它与任何事件或异步执行都没有关系。您可以定义IIFE,如下所示:
(function() {
// all your code here
// ...
})();
第一对括号function(){...}将括号内的代码转换为表达式。第二对括号调用表达式产生的函数。
IIFE
也可以描述为自调用匿名函数。它最常见的用法是限制通过var创建的变量的范围或封装上下文以避免名称冲突。
答案 18 :(得分:0)
使用自我唤起匿名函数的原因是它们永远不应该被其他代码调用,因为它们“设置”了要调用的代码(同时给函数和变量赋予了范围)。
换句话说,它们就像在程序开始时“制作类”的程序。在实例化(自动)之后,唯一可用的函数是匿名函数返回的函数。但是,所有函数都是其他'隐藏'函数仍然存在,以及任何状态(在范围创建期间设置的变量)。
非常酷。
答案 19 :(得分:0)
它称为IIFE-立即调用函数表达式。这是显示其语法和用法的示例。它用于确定变量的使用范围,直到该函数为止。
(function () {
function Question(q,a,c) {
this.q = q;
this.a = a;
this.c = c;
}
Question.prototype.displayQuestion = function() {
console.log(this.q);
for (var i = 0; i < this.a.length; i++) {
console.log(i+": "+this.a[i]);
}
}
Question.prototype.checkAnswer = function(ans) {
if (ans===this.c) {
console.log("correct");
} else {
console.log("incorrect");
}
}
var q1 = new Question('Is Javascript the coolest?', ['yes', 'no'], 0);
var q2 = new Question('Is python better than Javascript?', ['yes', 'no', 'both are same'], 2);
var q3 = new Question('Is Javascript the worst?', ['yes', 'no'], 1);
var questions = [q1, q2, q3];
var n = Math.floor(Math.random() * questions.length)
var answer = parseInt(prompt(questions[n].displayQuestion()));
questions[n].checkAnswer(answer);
})();
答案 20 :(得分:0)
使用ES6语法(为自己发帖,我一直登陆此页面寻找快速示例)
// simple
const simpleNumber = (() => {
return true ? 1 : 2
})()
// with param
const isPositiveNumber = ((number) => {
return number > 0 ? true : false
})(4)
答案 21 :(得分:0)
此功能称为自调用功能。自调用(也称为自执行)函数是无名(匿名)函数,在其定义后立即被调用(调用)。 Read more here
这些函数的作用是在定义函数后立即调用该函数,这样可以节省时间和额外的代码行(与在单独的行中调用相比)。
这里是一个示例:
(function() {
var x = 5 + 4;
console.log(x);
})();
答案 22 :(得分:0)
这是为什么要使用它的更深入的解释:
“使用IIFE的主要原因是为了获得数据隐私。由于JavaScript的var将变量作用域包含在其包含的函数中,因此IIFE中声明的任何变量都无法被外界访问。”
答案 23 :(得分:0)
这里已经有很多好的答案,但这是我的2美分:p
您可以将IIFE(立即调用函数表达式)用于:
避免污染全局命名空间。
IIFE(甚至任何常规函数)中定义的变量不会覆盖全局范围内的定义。
防止外部代码访问代码。
您只能在IIFE中访问您在IIFE中定义的所有内容。它可以防止代码被外部代码修改。外部代码只能访问作为函数结果或设置为外部变量的值的显式返回。
避免使用不需要重复使用的命名功能。 尽管可以在IIFE模式中使用命名函数,但是您不必这样做,因为通常不需要重复调用它。
对于Universal Module Definitions,在许多JS库中使用。请查看此question了解详情。
IIFE通常以以下方式使用:
(function(param){
//code here
})(args);
您可以在匿名函数周围省略括号()
,并在匿名函数之前使用void
运算符。
void function(param){
//code here
}(args);
答案 24 :(得分:-1)
通常,JavaScript代码在应用程序中具有全局范围。当我们在其中声明全局变量时,有可能在开发的某些其他区域中使用相同的重复变量用于其他目的。由于这种重复,可能会发生一些错误。所以我们可以通过使用立即调用函数表达式来避免这个全局变量,这个表达式是自执行表达式。当我们在 IIFE 表达式中创建我们的代码时,全局变量将像本地范围和局部变量一样。 / p>
我们可以通过两种方式创建 IIFE
(function () {
"use strict";
var app = angular.module("myModule", []);
}());
OR
(function () {
"use strict";
var app = angular.module("myModule", []);
})();
在上面的代码段中,“ var app ”现在是一个局部变量。
答案 25 :(得分:-1)
通常,我们在将函数写入程序后不会立即调用该函数。 用非常简单的术语来说,当您在函数创建后立即调用它时,它被称为IIFE-一个花哨的名字。
答案 26 :(得分:-1)
以下代码:
(function () {
})();
被称为立即调用的函数表达式(IIFE)。
之所以称为函数表达式,是因为Javascript中的( yourcode )
运算符将其强制为表达式。 函数表达式和函数声明之间的区别如下:
// declaration:
function declaredFunction () {}
// expressions:
// storing function into variable
const expressedFunction = function () {}
// Using () operator, which transforms the function into an expression
(function () {})
表达式只是一堆代码,可以将其评估为单个值。对于上述示例中的表达式,此值为单个函数对象。
有了一个表达式,该表达式的值等于一个函数对象,然后我们可以立即使用()
运算符调用该函数对象。例如:
(function() {
const foo = 10; // all variables inside here are scoped to the function block
console.log(foo);
})();
console.log(foo); // referenceError foo is scoped to the IIFE
当我们处理大型代码库和/或导入各种库时,命名冲突的可能性增加。当我们在IIFE内编写代码的某些相关部分(并因此使用相同的变量)时,所有变量和函数名都位于IIFE的函数括号内。这样可以减少命名冲突的机会,并使您更不小心地命名它们(例如,您不必给它们加上前缀)。
答案 27 :(得分:-1)
我认为2套括号让它有点混乱,但我在googles例子中看到了另一种用法,他们使用类似的东西,我希望这会帮助你更好地理解:
var app = window.app || (window.app = {});
console.log(app);
console.log(window.app);
因此,如果未定义windows.app
,则会立即执行window.app = {}
,因此在条件评估期间会为window.app
分配{}
,因此结果为{{ 1}}和app
现在变为window.app
,因此控制台输出为:
{}