您要问的是自调用函数,也称为 IIFE(立即调用函数表达式)。这与闭包不同。尽管它确实创建了一个闭包(实际上,javascript 中的所有函数都创建了闭包,而不仅仅是 IIFE)。
不过,您可能会混淆这两个问题是可以理解的,因为 IIFE 通常是在解释闭包的上下文中引入的。但请注意,它们是不同的东西。闭包是私有的、共享的“类全局”变量。IIFE 是在定义后立即调用的函数。
现在,IIFE 是如何工作的?线索就在名字里。这是“FE”IIFE - 函数表达式。
如您所知,在 javascript 中,有两种创建函数的方法 - 使用函数声明:
function foo () {}
并使用函数表达式:
foo = function () {}
函数表达式只是在表达式的上下文*中声明的函数。javascript中的表达式是什么?只是任何评估某事的陈述。
传统上,人们将表达式识别为:
=
标志右侧的任何东西
a = /* expression */
大括号里的任何东西
(/* expression */)
所以传统上这是声明函数表达式的两种“标准”方式:
foo = function(){}
和
(function(){})
第二种语法使执行表达式返回的函数对象变得容易。但是,实际上,表达式是 js 进行数学(或逻辑,无论如何都是数学)的任何地方。因此,在函数声明中添加运算符也会将其转换为表达式。以下是有效的,因为它们是一元运算符(意思是,它们在左侧没有任何东西是合法的):
!function(){}()
+function(){}()
-function(){}() // I especially like this one because it
// looks like a command line switch
typeof function(){}()
但是,如果您使用一些一次性值或变量,您也可以使用二元运算符。以下也有效:
x=function(){}()
0==function(){}()
1*function(){}()
2/function(){}()
哎呀,你甚至可以滥用三元运算符:
0?0:function(){}() // valid and works!
它没有什么神奇之处。它不是嵌入到 javascript 中的特定语法。就像(function(){}())
不是 IIFE 的特定语法。只是当在表达式中声明时,函数将自身作为可以立即调用的对象返回。
但我建议不要使用上述任何非标准形式。出于同样的原因,您问了这个问题 - 大多数 javascript 程序员不习惯看到它们,这可能会导致混淆。直到你问这个问题,我自己才意识到你可以做到这一点。尽管如此,了解何时需要编写诸如缩小器、代码生成器等内容还是很有用的。
* 我在这里使用的是传统定义中的“上下文”,而不是规范中定义的“上下文”的 javascript 特定含义。