【问题标题】:What are the different ways of writing an IIFE? What are their use cases?编写 IIFE 的不同方法是什么?他们的用例是什么?
【发布时间】:2016-02-12 13:58:38
【问题描述】:

我已经开始阅读this 的书了。第 2 章说编写 IIFE 有不同的方法:

!function (){}() 
~function (){}() 
+function (){}() 
-function (){}()
new function (){} 
1,function (){}() 
1&&function (){}() 
var i=function (){}()

作者说:

每种表现形式都有其独特的品质和优势——有些 字节数更少,连接更安全,每个有效且每个 可执行文件。

我是 JS 的新手。我知道 IIFE 是什么,但这些 IIFE 表格究竟是做什么的?

【问题讨论】:

标签: javascript function iife


【解决方案1】:

为什么要这样做?

在我们进入列表之前,让我们先从“为什么要这样做?”

答案是:将函数中的任何变量和函数声明保持为私有。通常这是为了避免全局变量(避免全局变量是一个好主意TM)。例如:

+function() {
    function foo() {
        /* ... */
    }

    foo();

    var answer = 42;
}();

感谢 IIFE(在此上下文中称为 作用域函数),fooanswer 不是全局变量。它们对函数内的代码是私有的,除非它们以某种方式导出。

即使不在全局范围内,您也可以这样做,只是为了避免污染您所在的范围。

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""nullundefinedNaN 或 @ 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(){}()

哇!

连续拥有多个; 是无害的,所以如果你从一个开始,就不太可能遇到麻烦。

【讨论】:

  • (function() {}) 表单如果前面是不带分号的非 II 函数表达式,可能会导致意外调用:var f = function(x) { console.log ("called with x: " + x) } /* new line, no semi-colon */ (function() { console.log("second") }())
  • 听起来像一个奇怪的边缘案例,但我已经看到它发生在野外。道德:如果您喜欢括号式的 IIFE,请始终使用分号(或者只是“始终使用分号”)。
  • @joews:其中许多可能会导致意外结果,因为前面的代码不正确终止,而不仅仅是(function...) 的代码。例如,前导分号是一种很好的防御,这就是我经常做的缩小。
  • @joews:感谢您的精彩说明,我已经在最后添加了完整的内容。
  • 啊,当然!之前我没有过多考虑运算符前缀。
【解决方案2】:

将多个文件合并为一个是一种优化。这里的想法是,如果前一个文件的最后一行没有以换行符结尾,那么这个文件的第一行从一行的中间开始。

在函数允许它仍然正常工作之前添加诸如; 之类的东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-14
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多