我曾经知道这是什么意思,但是我现在正在努力...
这基本上是在说document.onload
什么吗?
(function () {
})();
我曾经知道这是什么意思,但是我现在正在努力...
这基本上是在说document.onload
什么吗?
(function () {
})();
Answers:
它是立即调用的函数表达式,简称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)
该函数在创建后立即执行,而不是在解析之后执行。在执行脚本块中的任何代码之前,都将对其进行分析。同样,解析代码并不会自动意味着它已被执行,例如,如果IIFE在函数内部,那么直到调用该函数后,它才会被执行。
更新 由于这是一个非常受欢迎的话题,值得一提的是,IIFE也可以使用ES6的arrow函数编写(就像Gajus 在评论中指出的那样):
((foo) => {
// do something with foo here foo
})('foo value')
function(){ var foo = '5'; }
它只是创建后立即执行的匿名函数。
就像您将其分配给变量,然后在没有变量的情况下立即使用它:
var f = function () {
};
f();
在jQuery中,您可能会想到类似的构造:
$(function(){
});
这是绑定ready
事件的简短形式:
$(document).ready(function(){
});
但是以上两个构造不是IIFE。
立即调用的函数表达式(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
31.new
“无效语法
;(function(){}());
就是说立即执行。
所以如果我这样做:
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
该构造称为立即调用函数表达式(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
限于使用大括号创建的代码块{...}
。
我称它为“监狱监狱”。
(function () {
})();
这称为IIFE(立即调用函数表达式)。这是著名的JavaScript设计模式之一,它是现代Module模式的核心和灵魂。顾名思义,它在创建后立即执行。这种模式创建了隔离的或私有的执行范围。
ECMAScript 6之前的JavaScript使用词法作用域,因此IIFE用于模拟块作用域。(通过引入let
和const
关键字,可以使用ECMAScript 6进行块作用域定义。)
有关词法作用域的问题的参考
使用IIFE的的性能优势是通过像常用的全局对象的能力window
,document
通过减少范围查找等作为参数。(请记住,JavaScript在本地范围内查找属性,并在整个范围内一直查找直到全局范围)。因此,在本地范围内访问全局对象可以减少如下所示的查找时间。
(function (globalObj) {
//Access the globalObj
})(window);
不,此构造仅创建命名范围。如果您将它分成几部分,则可以看到您有一个外部
(...)();
那是一个函数调用。在括号内,您具有:
function() {}
那是一个匿名函数。在构造内部用var声明的所有内容仅在同一构造内部可见,并且不会污染全局名称空间。
这是Javascript中立即调用的函数表达式:
要了解JS中的IIFE,让我们分解一下:
a = 10 output = 10 (1+3) output = 4
// Function Expression var greet = function(name){ return 'Namaste' + ' ' + name; } greet('Santosh');
函数表达式的工作原理:
-JS引擎首次运行时(执行上下文-创建阶段),该函数(在上面=的右侧)不会执行或存储在内存中。JS引擎为变量“ greet”分配了“ undefined”值。
-在执行过程中(执行上下文-执行阶段),将动态创建功能对象(尚未执行),将其分配给'greet'变量,并且可以使用'greet('somename')'进行调用。
3.立即调用功能表达式:
例:
// IIFE
var greeting = function(name) {
return 'Namaste' + ' ' + name;
}('Santosh')
console.log(greeting) // Namaste Santosh.
IIFE的工作方式:
-在函数声明后立即注意'()'。每个功能对象都具有可调用的“ CODE”属性。我们可以使用()大括号来调用它(或调用它)。
-因此,在执行过程中(执行上下文-执行阶段),将同时创建并执行功能对象
-因此,现在,问候变量(而不具有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可以帮助我们编写安全的代码,而不会在无意间与全局对象发生冲突。
那是一个自调用的匿名函数。
可以使函数表达式“自调用”。
自调用表达式将自动调用(启动),而不被调用。
如果函数表达式后跟(),则函数表达式将自动执行。
您不能自行调用函数声明。
(function named(){console.log("Hello");}());
<-自执行命名函数
这是自调用匿名功能。它在定义时执行。这意味着已定义此函数,并在定义后立即调用自身。
语法的解释是:第一个()
括号内的函数是没有名称的函数,通过下一个();
括号,您可以理解它在定义时被调用。您可以在第二个()
括号中传递任何参数,该参数将在第一个括号中的函数中获取。请参阅以下示例:
(function(obj){
// Do something with this obj
})(object);
在这里,您正在传递的“对象”将通过“ obj”在函数内访问,就像您在函数签名中获取它一样。
从这里开始:
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);
})();
并不需要比这更复杂。
Uncaught SyntaxError: Unexpected token )
是箭头函数,而不是任何提及。您能否与它一起抛出箭头功能错误?
自执行匿名功能。它在创建后立即执行。
一个有用的简短示例是:
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);
因此,您不必一次创建一个列表,而只需创建一次(减少开销)。
自我执行功能通常用于封装上下文并避免名称冲突。您在(function(){..})()内部定义的任何变量都不是全局变量。
编码
var same_name = 1;
var myVar = (function() {
var same_name = 2;
console.log(same_name);
})();
console.log(same_name);
产生以下输出:
2
1
通过使用此语法,可以避免与JavaScript代码中其他地方声明的全局变量冲突。
var same_name = 1; var myVar = function() { var same_name = 2; console.log(same_name); }; myVar(); console.log(same_name);
会有相同的结果。
它称为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);
})();
IIFE(立即调用的函数表达式)是一个在脚本加载并消失后立即执行的函数。
考虑下面的函数,该函数写在名为iife.js的文件中
(function(){
console.log("Hello Stackoverflow!");
})();
上面的代码将在您加载iife.js后立即执行,并显示“ Hello Stackoverflow!在开发人员工具的控制台上。
有关详细说明,请参见立即调用函数表达式(IIFE)。
另一个用例是记忆,其中缓存对象不是全局的:
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];
}
}
})();
如下代码:
(function () {
})();
被称为立即调用函数表达式(IIFE)。
之所以称为函数表达式,是因为( yourcode )
Javascript中的运算符将其强制为表达式。函数表达式和函数声明之间的区别如下:
// 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的函数括号内。这减少了命名冲突的机会,并使您更不小心地命名它们(例如,您不必给它们加上前缀)。
这是为什么要使用它的更深入的解释:
“使用IIFE的主要原因是为了获得数据隐私。由于JavaScript的var将变量作用域包含在其包含的函数中,因此IIFE中声明的任何变量都无法被外界访问。”
它是一个函数表达式,代表立即调用函数表达式(IIFE)。IIFE只是创建后立即执行的功能。因此,在必须等待该函数被调用才能执行该函数的情况下,会立即执行IIFE。让我们以示例的方式构造IIFE。假设我们有一个add函数,该函数将两个整数作为args并返回总和,使add函数成为IIFE,
步骤1:定义功能
function add (a, b){
return a+b;
}
add(5,5);
步骤2:通过将整个函数声明包装在括号中来调用函数
(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>
通常,JavaScript代码在应用程序中具有全局作用域。当我们在其中声明全局变量时,就有可能在开发的其他区域中将相同的重复变量用于其他目的。由于此重复,可能会发生一些错误。因此我们可以通过立即调用函数expression来避免使用该全局变量,该表达式是自执行表达式。当我们在该IIFE表达式中编写代码时,全局变量将类似于局部作用域和局部变量。
创建IIFE的两种方法
(function () {
"use strict";
var app = angular.module("myModule", []);
}());
要么
(function () {
"use strict";
var app = angular.module("myModule", []);
})();
在上面的代码片段中,“ var app ”现在是一个局部变量。