Javascript () operator invokes function
我一直在使用javascript一段时间,我开始意识到我使用该语言有多糟糕。 它的一些更高级的方面是关于光,如闭合,模块模式等。
有人可以解释()操作符在放置在函数末尾时是如何工作的,也就是为什么它会立即调用它 - 我以前没有看过这个并且对这实际上是如何工作感到困惑。
如:
1 2 3 | var myFunct = function() { alert("here"); }(); |
最后的()将立即调用该函数。
函数是一个对象。使用
1 2 3 4 5 6 7 8 9 | function foo() { return 2; } typeof foo() ="number" typeof foo ="function" |
Javascript函数是一流的对象。它们可以存储,传递和返回。由于它们是功能,它们也可以被调用。
所以你可以这样写:
1 2 3 4 5 | var f = function(message) { window.alert(message); } f("Hello, world!"); |
这会创建一个匿名函数对象并将其存储到
您还可以创建一个匿名函数对象并立即调用它,而不将其存储在变量中:
1 2 3 | (function(message) { window.alert(message); })("Hello, world!"); |
这只是调用函数的语法:
1 2 | function foo() { alert('Purple is a nice colour') } foo(); // Invokes the 'foo' function |
同样,因为在Javascript函数中是第一类对象,可以这样做:
1 2 | var foo = function() { alert('I like camels') }; foo(); // Invokes the function that the variable 'foo' has a reference to |
甚至可以在不使用中间变量的情况下表达(因为函数是对象):
1 | (function () { alert('Ponies are cool') })(); // Creates a function object, then invokes it |
()构造意味着"函数调用"。关于JavaScript的一些与其他语言不同的是标识符不是你可以作为函数调用的唯一东西。所以从C来看,这样的东西可能看起来很熟悉:
1 | fnName(); |
但是在JavaScript中,任何表达式都可以求值为函数,这意味着它可以作为函数调用来调用。像这样:
1 | (function () {/*do something*/})(); |
函数表达式周围的括号是分组表达式所必需的,这样第二组括号就是对第一组括号中表达式的函数调用。
在JavaScript中,函数也是对象,通过对它应用()运算符,您将调用该函数,并且调用将计算为从函数返回的结果。
因此,让我们分解你的陈述,即:
1 2 3 | var myFunct = function() { alert("here"); }(); |
首先,你定义一个函数,所以让我们"重构"这个,使部分变得更清晰。
1 2 3 4 | var myFunctionDeclaration = function() { alert("here"); }; var myFunct = myFunctionDeclaration(); |
现在,应该更容易看到您在代码中调用该函数。
函数声明不是需要自己的语句,而是可以用作返回函数对象的表达式。
基本上你的代码是这样的:
1 2 3 | var myFunct = (expression that produces function object)(); ^^ +--- invoke the function |
这意味着您可以将它们链接在一起。如果你的函数返回另一个函数,你也可以在同一个语句中调用这个新函数。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 | var myFunct = function() { alert("here"); return function() { return 10; }; }()(); ^ ^ | +-- calls the inner function, that was returned when calling the outer | function | +---- calls the outer function, which returns a new function object // myFunct ends up being 10 |
如果()没有调用该函数,则必须使用其他语法。它只是函数调用的语法选择,因为它熟悉许多早期语言。参数(如果有的话)放在括号中。
很难看到你如何在没有遇到函数调用的情况下在Javascript中做任何事情。
调用函数并不是那么多(尽管实际上是这样)但是参数被传递给函数并且正在评估函数。
在自我调用的情况下,我承认它确实令人困惑。但这是对正在发生的事情的分解。假设我将一个匿名函数分配给变量。
1 2 3 | var myFunction1 = function () { console.log("function assigned to variable object myFunction1"); }; |
允许它成为匿名函数的原因是因为它存储在变量myFunction1中,将其转换为具有属性myFunction1的对象和作为属性值分配给变量的函数表达式。
In essence we have var myFunction1 rewritten to global = { myFunction1 : (function () { return 1+2; })(); }
Ok.
我不需要将函数命名为与未分配给变量的函数相同的编码模式,因为我可以通过变量名称来调用它,因为变量是一个对象。这很重要,因为我们依赖于JS中几乎所有东西都被定义为多种对象类型(即函数,变量名,布尔值,数字,符号等)的概念。
1 2 3 | function () { console.log("function assigned to variable object myFunction1"); }; |
这不会执行,因为表达式未指定为表达式。它现在被声明,因为你开始使用关键字函数告诉解释器我正在声明这个函数。但是你必须在所有函数声明中给出一个名称以供解释器引用。所以();什么时候跑步没什么可走的。没有要评估的对象或参数,你没有命名这个函数,因此没有引用它只是一个ghost函数。可以通过点语法的形式来考虑它,您可以通过对象访问对象属性。属性
包装函数的括号现在是匿名执行的参数(function(){})。该参数只是简写,表示这是一个表达式。然后你通过执行()来访问参数,因为我已经访问了函数中的函数并且可以访问该函数中的任何参数。
1 2 3 4 5 6 7 8 9 10 11 | (function (a){})(a); //Opening the initial parameter which is a function and then internally accessing the function params. (1+2); //Will evaluate to 3 (1+2)(); //Will not run because I've not only accessed the param of the expression but I've now told it to evaluate the internal expression in that param and there is none (function () { return 1+2; })(); //Will run because I've accessed the initial param, which is a function and asked it to execute it's internal expression in the braces return 1+2 |
本质上,解释器运行布尔值。问题是:
1)参数是否存在?是
2)有内部表达吗?不,因为它不是一个功能
这就是为什么 !也用于匿名函数声明,即表达式写入。
1 2 3 4 5 6 7 | ! function () { console.log("This is true and ran the expression" }(); //Is it not a function? True //Evaluate the expression since it is not a function function () { console.log("This will never log because it is not true" }(); //Is it a function? False //Do not evaluate the expression since it is false |
现在我们知道,()不能单独定义为调用操作符,而在基本假设中可能有意义,因为它在几个容量中依赖于编码模式,让我们继续前进。
在声明函数的参数/参数时,您也使用()。
1 | function myFunction2 (a,b) { sum = a+b; console.log(sum) }; |
在这个例子中,我们使用()来定义函数的参数/参数以包括& b,我们稍后将在代码中引用。这些类似于脚本中定义的变量,但其根本区别在于能够将参数定义传递给它们,而在分配商店时不记得赋值。当您可以在任何时候将值重新赋值给变量时,这似乎微不足道,但实际上我们希望获得最简单的执行形式。这就是为什么存在这种原因,以及另一个将在后面简要讨论的提升核心概念。
重新分配值只是浪费时间,并且可预见地导致编码中的无数错误(由于范围问题和其他诸如我们将不会进入的提升)以及不需要的额外处理。请记住,每种编码语言都是为解决问题而构建的,它们的进一步版本和迭代的目的是使解决方案更加高效,同时也适应新的方法和结构(我们也不会为了这个问题)。
所以我们现在知道()不一定是一个单一的调用方法,而是一个允许在JS编码中声明和赋值声明的多方法。
现在让我们看一个匿名函数:
1 2 3 4 5 | ( function () { console.log("My anonymous function is not assigned to a variable"); } ) (); |
我们在这做了什么?好吧,它本质上很简单,函数包含在()中,我们现在知道它具有声明和调用的权力,然后为参数赋值。所以我们实际上有这个函数的2个参数。第一个是匿名函数,因此没有可用于调用或调用此函数的名称。然后我们在没有参数的单词函数之后有()(如果需要,可以添加参数)。
现在这里是一个匿名函数声明的警告。这只是表达!我们知道表达式只是一组数字,符号和运算符,它们组合在一起以评估和显示值。这样:
1 2 | 1 + 2 = 3; //This is an expression function (b) { b = 1+2; console.log(b) }(); //This is the expression of 1+2 which is 3 and then that value is assigned to b |
这一点很重要,因为表达式与对象有很大不同。对于存储它们的对象,可以调用和操作它们。即使命名,匿名函数仍然只是一个表达式。它永远不会转换为对象。例如:
(function anonFunction(b){b = 1 + 2; console.log(b)})();
anonFunction();
将导致3和anonFunction未定义。这是因为该函数只是一个自运行表达式,仅表示该实例的值。解释器不会将此函数记录为对象。为此,您需要将表达式分配给变量,该变量又使变量成为包含表达式anonFunction的对象。
1 2 | var myDefinedFunction = function (b) { b = 1+2; console.log(b) }; myDefinedFunction(); |
您会注意到外侧括号和末尾括号已被删除。它们不是必需的并且会导致错误,因为我们不希望该函数只是一个自运行的表达式。我们希望将函数分配给一个对象。在实际应用中,最有效的方法是为函数分配名称。实际上它们都产生相同的对象值。 var和function都包含函数的表达式:
1 | (b) { b = 1+2; console.log(b) }; |
这里的核心差异是范围和提升。我们先讨论一下吊装。在运行任何代码之前,所有功能都被提升到顶部。然后,在定义之前引用但在代码中引用的任何变量都会被提升,但定义的值不会被提升。仅在遇到时分配该值。因此,创建命名函数优先于任何其他函数,包括非匿名函数表达式。
1 2 3 4 | myFunExpression; myHelloFun(); var myFunExpression = function () { console.log("hello") }; function myHelloFun () { console.log('Hello from function') } |
你会得到"Hello from function"并且未定义,因为var值是在var执行/调用之后分配的。此外,您不能对变量使用()因为变量本身不是函数,它包含一个函数。因此,您无法评估变量,因为没有要评估的表达式或要在表达式中传递的参数用于评估目的。
因为你不能使用()执行变量。在函数传递参数意义上的范围也无法完成。它的用处仅在于调用已赋给变量的表达式。可以传递参数的唯一方法是它是否已经在函数表达式中,并且该参数/参数能够获取函数范围可用性中的参数。
所以总结这个详尽的解释。 ()运算符是参数/参数持有者和依赖于编码模式的评估/执行运算符。它不仅仅用于调用。
在匿名函数中使用时:
1 2 3 4 5 6 7 8 | (function (a) { return a; } ) (2 +" hello"); //The value"2 hello" string is passed for evaluation return the value (function (a,b) { return b; } ) (2 +" hello","my b value"); //The value"my b value" is passed to the 2nd parameter for evaluation (function (a,b) { return b; } ) (); //undefined because the evaluation of return has no passed arguments |
好。
我假设你的意思是一个立即执行的anonumous函数(根据你的编辑,我的假设是正确的):
1 | (function(){...})(); |
它适用于引用函数的任何值,例如:
1 2 3 4 5 6 | var x = function(){}; x(); function y(){} var z = y; z(); |
甚至是一个返回函数引用的函数:
1 2 3 4 | function a() { return function(){}; } a()(); |