为什么要这样做?
在我们进入列表之前,让我们先从“为什么要这样做?”
答案是:将函数中的任何变量和函数声明保持为私有。通常这是为了避免全局变量(避免全局变量是一个好主意TM)。例如:
+function() {
function foo() {
/* ... */
}
foo();
var answer = 42;
}();
感谢 IIFE(在此上下文中称为 作用域函数),foo 和 answer 不是全局变量。它们对函数内的代码是私有的,除非它们以某种方式导出。
即使不在全局范围内,您也可以这样做,只是为了避免污染您所在的范围。
IIFE 通常还有其他用途,但您引用的样式通常用于范围界定。
例子
作者戏剧性地夸大了“每个人都有自己独特的品质和优势”。
除非您使用返回值,否则这些都是完全相同的:
!function (){}()
~function (){}()
+function (){}()
-function (){}()
1,function (){}()
1&&function (){}()
其中的代码在函数范围内运行。
我们也可以将这些添加到该列表中:
(function(){}())
(function(){})()
0||function (){}()
1^function(){}() // any binary math operator in place of ^ also works
当然,以上所有的1 并不特殊。对于大多数人来说,可以是任何数字(或其他任何数字),但使用 && 的数字不适用于 0、""、null、undefined、NaN 或 @ 987654333@(该函数无法运行)。同样,带有0||... 的那个只要开头的值是假的就可以工作。
在这个:
var i=function (){}()
...唯一的区别是它声明了一个变量i,它存储了返回值。当然,这可能会有很大的不同。考虑这个更明显的版本:
var MyPseudoNamespace = function() {
// ...
return { /* nifty "namespace" stuff here */ };
})();
最后:
new function (){}
这会创建一个新对象,然后调用将this 设置为新对象的函数。如果你不在函数中使用this,那是完全没有意义的。如果你这样做了,那么它是否有用取决于你用this 做什么。
注意:如果您无法控制的代码在您的作用域函数之前出现(例如,当您合并和缩小文件时),最好开始所有用; 关闭,例如:
;!function (){}()
;~function (){}()
;+function (){}()
;-function (){}()
;1,function (){}()
;1&&function (){}()
;(function(){}())
;(function(){})()
;0||function (){}()
;1^function(){}() // any binary math operator in place of ^ also works
其中一些在技术上并不需要,但大多数都需要。没有它们的副作用可能是微妙的,也可能是灾难性的。考虑:
代码前的代码:
obj.prop = function() {
// Do something big and awful
}
然后你的代码:
(function(){}())
自动分号插入不会启动!结果? obj.prop 函数被调用,我们的 IIFE 作为参数传递给它。这样会更明显:
obj.prop = function() {
// Do something big and awful
}(function(){}())
看看() 现在是如何调用函数的?
同样:
obj.criticalValue = 42
然后
+function(){}()
突然间,criticalValue 搞砸了。为什么?因为:
obj.criticalValue = 42+function(){}()
哇!
连续拥有多个; 是无害的,所以如果你从一个开始,就不太可能遇到麻烦。