我想知道这是什么意思:
(function () {
})();
这是在说document。onload吗?
我想知道这是什么意思:
(function () {
})();
这是在说document。onload吗?
它是一个立即调用的函数表达式,简称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的箭头函数来编写(就像Gajus在评论中指出的那样):
((foo) => {
// do something with foo here foo
})('foo value')
也就是说立即执行。
所以如果我这样做:
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
它声明了一个匿名函数,然后调用它:
(function (local_arg) {
// anonymous function
console.log(local_arg);
})(arg);
这是一个自调用匿名函数。
查看W3Schools对自调用函数的解释。
函数表达式可以“自调用”。 自动调用(启动)自调用表达式,无需 被称为。 函数表达式将自动执行 后面跟着()。 不能自调用函数声明。
不,这个构造只是为命名创建了一个作用域。如果你把它分成几部分,你可以看到你有一个外部
(...)();
这是一个函数调用。括号内是:
function() {}
这是一个匿名函数。在构造中使用var声明的所有内容将只在同一构造中可见,并且不会污染全局名称空间。
自执行匿名函数。它在创建时立即执行。
举个简单的例子,说明这个方法很有用:
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);
因此,不是每次都创建一个列表,而是只创建一次(开销更少)。
它只是一个匿名函数,在创建后立即执行。
这就像你把它赋值给一个变量,然后在后面使用它,只是没有变量:
var f = function () {
};
f();
在jQuery中,有一个类似的构造,你可能会想到:
$(function(){
});
这是绑定就绪事件的简写形式:
$(document).ready(function(){
});
但是上面的两个结构都不是iife。
自执行函数通常用于封装上下文和避免名称混淆。在(function(){..})()中定义的任何变量都不是全局变量。
的代码
var same_name = 1;
var myVar = (function() {
var same_name = 2;
console.log(same_name);
})();
console.log(same_name);
产生如下输出:
2
1
通过使用这种语法,可以避免与JavaScript代码中其他地方声明的全局变量发生冲突。
立即调用的函数表达式(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(obj){
// Do something with this obj
})(object);
在这里,你传递的“对象”将在函数中通过“obj”访问,因为你在函数签名中抓取它。
(function () {
})();
这被称为IIFE(立即调用函数表达式)。它是著名的JavaScript设计模式之一,是现代Module模式的核心和灵魂。顾名思义,它在创建后立即执行。此模式创建一个隔离的或私有的执行范围。
在ECMAScript 6之前的JavaScript使用词法作用域,因此IIFE用于模拟块作用域。(在ECMAScript 6中,通过引入let和const关键字,块范围是可能的。) 关于词汇范围问题的参考
用IIFE模拟块作用域
使用IIFE的性能优势是能够通过减少范围查找来将常用的全局对象(如window、document等)作为参数传递。(请记住,JavaScript在局部作用域和全局作用域的链中寻找属性)。因此,在局部作用域中访问全局对象可以减少查找时间,如下所示。
(function (globalObj) {
//Access the globalObj
})(window);
还有一个用例是内存,缓存对象不是全局的:
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];
}
}
})();
该构造称为立即调用函数表达式(IIFE),这意味着它将立即执行。可以把它看作是解释器到达该函数时自动调用的函数。
最常见的用例:
它最常见的用例之一是限制通过var创建的变量的作用域。通过var创建的变量的作用域仅限于一个函数,因此这个构造(这是一个围绕某些代码的函数包装器)将确保你的变量作用域不会泄漏到该函数中。
在下面的例子中,count在立即调用的函数之外是不可用的,即count的作用域不会泄漏到函数之外。您应该得到一个ReferenceError,如果您尝试在立即调用的函数之外访问它。
(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); // ReferenceError: count is not defined
在本例中,我们使用let定义count变量,使count限制在我们用花括号{…}创建的代码块中。
我称之为“卷毛监狱”。
IIFE(立即调用函数表达式)是一个在脚本加载和退出时立即执行的函数。
考虑下面写在life .js文件中的函数
(function(){
console.log("Hello Stackoverflow!");
})();
上面的代码将在你加载life .js时立即执行,并打印'Hello Stackoverflow!在开发人员工具控制台。
有关详细解释,请参阅立即调用函数表达式(IIFE)
从这里开始:
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*
立即调用函数——哎呀:
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);
})();
不需要比这更复杂了。
立即调用函数表达式(IIFE)是一种在创建时立即执行的函数。它与任何事件或异步执行没有关联。你可以定义一个IIFE,如下所示:
(function() {
// all your code here
// ...
})();
第一对括号函数(){…}将括号内的代码转换为表达式。第二对括号调用由表达式生成的函数。
IIFE也可以描述为一个自我调用的匿名函数。它最常见的用法是限制通过var创建的变量的作用域,或者封装上下文以避免名称冲突。
使用自调用匿名函数的原因是它们永远不应该被其他代码调用,因为它们“设置”了要调用的代码(同时为函数和变量提供了作用域)。
换句话说,它们就像在程序开始时“创建类”的程序。在它们被实例化(自动)之后,唯一可用的函数是匿名函数返回的那些函数。然而,所有其他“隐藏”函数仍然存在,以及任何状态(在作用域创建期间设置的变量)。
非常酷。
Normally, JavaScript code has global scope in the application. When we declare global variable in it, there is a chance for using the same duplicate variable in some other area of the development for some other purpose. Because of this duplication there may happen some error. So we can avoid this global variables by using immediately invoking function expression , this expression is self-executing expression.When we make our code inside this IIFE expression global variable will be like local scope and local variable.
我们可以通过两种方式创建IIFE
(function () {
"use strict";
var app = angular.module("myModule", []);
}());
OR
(function () {
"use strict";
var app = angular.module("myModule", []);
})();
在上面的代码片段中,“var app”现在是一个局部变量。
这是Javascript中立即调用的函数表达式:
为了理解JS中的IIFE,让我们分解一下:
表达式:返回值的东西 示例:在chrome控制台中尝试以下操作。这些是JS中的表达式。
A = 10 输出= 10 (1 + 3) 输出= 4
函数表达式: 例子:
函数表达式 var greet = function(name){ 返回“Namaste” + ' ' + 名称; } 问候(“桑托什”);
函数表达式如何工作: - JS引擎第一次运行时(执行上下文-创建阶段),这个函数(上面=右侧)不会被执行或存储在内存中。变量'greet'被JS引擎赋值为'undefined'。 -在执行期间(执行上下文-执行阶段),函数对象是动态创建的(尚未执行),被分配给'greet'变量,可以使用'greet(' someename ')'调用。
3.立即调用的函数表达式:
例子:
// IIFE
var greeting = function(name) {
return 'Namaste' + ' ' + name;
}('Santosh')
console.log(greeting) // Namaste Santosh.
IIFE如何运作: -注意函数声明后面的'()'。每个函数对象都有一个可调用的'CODE'属性。我们可以使用大括号'()'调用它。 -所以这里,在执行期间(执行上下文-执行阶段),函数对象被创建并同时执行 -所以现在,greeting变量没有函数对象,而是有它的返回值(一个字符串)
JS中IIFE的典型用例:
下面的IIFE模式是非常常用的。
// IIFE
// Spelling of Function was not correct , result into error
(function (name) {
var greeting = 'Namaste';
console.log(greeting + ' ' + name);
})('Santosh');
我们在这里做两件事。 a)将函数表达式包装在大括号()中。这将告诉语法解析器放在()中的whatever是一个表达式(在本例中是函数表达式),并且是一个有效的代码。 b)我们同时调用这个函数,在它的末尾使用()。
因此,这个函数同时被创建和执行(IIFE)。
IIFE的重要用例:
IIFE使我们的代码安全。 -作为一个函数,IIFE有自己的执行上下文,这意味着在它内部创建的所有变量都是这个函数的局部变量,不与全局执行上下文共享。
假设我的应用程序中使用了另一个JS文件(test1.js)和life . 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帮助我们编写安全的代码,这样我们就不会无意中与全局对象发生冲突。
以下代码:
(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 () {})
表达式只是一组可以求值为单个值的代码。对于上面例子中的表达式,这个值是一个单独的函数对象。
在得到表达式后,计算结果为函数对象,然后可以立即使用()操作符调用函数对象。例如:
(函数(){ Const foo = 10;//这里的所有变量都是函数块的作用域 console.log (foo); }) (); console.log (foo);// referenceError foo的作用域是IIFE
为什么这个有用?
当我们处理大型代码库和/或导入各种库时,命名冲突的几率会增加。当我们在IIFE中编写相关(因此使用相同的变量)的代码的某些部分时,所有的变量和函数名都被限定在IIFE的函数括号内。这减少了命名冲突的可能性,让你在命名时更粗心(例如,你不必在它们前面加上前缀)。
它被称为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);
})();
在ES6语法中(为自己发帖,因为我一直登陆这个页面寻找一个快速的例子):
// simple
const simpleNumber = (() => {
return true ? 1 : 2
})()
// with param
const isPositiveNumber = ((number) => {
return number > 0 ? true : false
})(4)
这个函数称为自调用函数。自调用(也称为自执行)函数是在定义之后立即调用(已调用)的无名(匿名)函数。点击这里阅读更多
这些函数的作用是,当函数被定义时,函数立即被调用,这节省了时间和额外的代码行(与在单独的行上调用相比)。
这里有一个例子:
(函数(){ Var x = 5 + 4; console.log (x); }) ();
这是一个更深入的解释,为什么你会使用这个:
“使用IIFE的主要原因是确保数据隐私。因为JavaScript的var将变量限定在包含变量的函数内,所以任何在IIFE中声明的变量都不能被外部世界访问。”
http://adripofjavascript.com/blog/drips/an-introduction-to-iffes-immediately-invoked-function-expressions.html
它是一个函数表达式,它代表立即调用函数表达式(IIFE)。IIFE只是一个在创建后立即执行的函数。因此,函数不必等到调用它才能执行,而是立即执行IIFE。让我们通过示例来构造IIFE。假设我们有一个add函数,它接受两个整数作为参数并返回和 让我们把add函数放到IIFE中,
步骤1:定义函数
function add (a, b){
return a+b;
}
add(5,5);
Step2:通过将整个函数声明包装到圆括号中来调用函数
(function add (a, b){
return a+b;
})
//add(5,5);
步骤3:要立即调用函数,只需从调用中删除'add'文本。
(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:重新声明不可配置的全局属性文档。
但是如果你想要声明一个名为documentmet的变量,你可以使用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>
输出:
让我们尝试另一个例子,假设我们有一个计算器对象像bellow-
<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:计算器。Mul不是if .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>
输出:
这里已经有很多很好的答案了,但这里是我的2美分:p
你可以使用IIFE(立即调用函数表达式):
Avoiding pollution in the global namespace. Variables defined in IIFE (or even any normal function) don't overwrite definitions in global scope. Protecting code from being accessed by outer code. Everything that you define within the IIFE can be only be accessed within the IIFE. It protects code from being modified by outer code. Only what you explicitly return as the result of function or set as value to outer variables is accessible by outer code. Avoid naming functions that you don't need to use repeatedly. Though it's possible to use a named function in IIFE pattern you don't do it as there is no need to call it repeatedly, generally. For Universal Module Definitions which is used in many JS libraries. Check this question for details.
IIFE通常以以下方式使用:
(function(param){
//code here
})(args);
您可以省略匿名函数周围的括号(),并在匿名函数之前使用void运算符。
void function(param){
//code here
}(args);
TL;DR:表达式可以括在圆括号中,如果函数的表达式和块形式组合在一起,则会与函数调用冲突。
我喜欢反例,因为它们描绘了一幅伟大的逻辑图景,而其他人没有列出任何反例。你可能会问,“为什么浏览器不能看到function(){}(),而只是假设它是一个表达式?”让我们用三个例子来比较这个问题。
var x; //这里fibonacci是一个block函数 函数fibonacci(x) { Var值= x < 2 ?X: fibonacci(X -1) + fibonacci(X -2); if (x === 9) console.log("The " + x + "th fibonacci is: " + value); 返回值; } (x = 9); console.log(" x的值:" + x); Console.log ("fibonacci is a(n) ")+ typeof fibonacci);
当我们将函数转换为表达式时,观察事情是如何变化的。
var x; //这里fibonacci是一个函数表达式 函数fibonacci(x) { Var值= x < 2 ?X: fibonacci(X -1) + fibonacci(X -2); if (x === 9) console.log("The " + x + "th fibonacci is: " + value); 返回值; }) (x = 9); console.log(" x的值:" + x); Console.log ("fibonacci is a(n) ")+ typeof fibonacci);
当你使用not-operator而不是圆括号时,也会发生同样的事情,因为这两个操作符都将语句转换为表达式:
var x; //这里fibonacci是一个函数表达式 ! 函数fibonacci(x) { Var值= x < 2 ?X: fibonacci(X -1) + fibonacci(X -2); if (x === 9) console.log("The " + x + "th fibonacci is: " + value); 返回值; } (x = 9); console.log(" x的值:" + x); Console.log ("fibonacci is a(n) ")+ typeof fibonacci);
通过将函数转换为表达式,它由它下面的两行(x = 9)执行。由于表达式函数和块函数的行为是分开的,所以这两个例子都运行得很好,没有歧义(规范方面)。
名字的作用域
另一个重要的观察是,命名块函数对整个作用域可见,而函数表达式只对其本身可见。换句话说,fibonacci只对第一个示例中的最后一个console.log是块时可见。在这三个例子中,fibonacci对自身是可见的,允许fibonacci调用自身,这是递归。
箭头功能
逻辑的另一个方面是箭头函数。如果块函数和表达式函数的定义合并在一起,规范将不得不包括箭头函数的任意规则和例外:
函数hello() {console.log(" hello World")} (x) => console.log("hello " + x) console.log("如果你正在阅读,没有发生错误");
虽然函数块工作正常,但函数表达式后面跟着箭头函数会产生语法错误:
! 函数hello() {console.log(" hello World")} (x) => console.log("hello " + x) console.log("如果你正在阅读,没有发生错误");
这里,第二行的(x)是调用前一行的函数还是箭头函数的函数参数是不明确的。
请注意,箭头函数多年来确实符合ECMAScript标准,在语言的初始设计中并不是一个因素;我的观点是,表达式函数和块函数之间的区别有助于JavaScript语法更有逻辑性和连贯性。