为什么在 IIFE 中使用 `+`(加号)或 `!`(逻辑非)运算符?

Why use the `+` (plus) or `!` (logical not) operator in an IIFE?

我知道 IIFE 的典型形式是:

(function(){/* code */})()

不过,最近我发现了一个新的:

!function(){/* code */}()
+function(){/* code */}()

它也可以用作 IIFE。

我认为第一个 ! 使值成为布尔值,所以代码等同于 true(),而第二个 + 使值成为一个数字,所以代码与NaN()相同?但是 true()NaN() 不可能工作,而上面两种形式工作得很好。

这两种形式的 IIFE 是如何工作的?

!function() {}()+function() {}() 的情况下 JavaScript 将首先计算给定 statement/IIFE 的右手边,然后转换 return 的值在 ! 的情况下将 IIFE 转换为布尔值,或者在 + 的情况下输入数字。 如果 IIFE returns 一个布尔值 ! 将取反 return 值。

例子

console.log(
  !function() {
    return "something";
  }()
); 

/**
!function() {
  return "something";
}()

evaluates to

!"something" and not true() or false()

lastly !"something" is equivalent to false
*/

有很多方法可以让函数在定义后立即执行。常见的事情是你必须确保函数不被解释为函数 statement,而是解释为函数 expression.

通过在函数关键字前加上一元运算符,如 !+ 或任何其他一元运算符(~-void、 ...等)你避免 function 被解释为 语句 .

赋值也有效:

var x = function(){/* code */}()

或数组文字:

[function(){/* code */}()]

或将其作为参数传递给(廉价)函数:

Object(function(){/* code */}())

或者应用二元运算符,前提是函数表达式是第二个操作数而不是第一个。这里使用逗号运算符:

0,function(){/* code */}()

function 关键字具有双重目的。根据您使用它的上下文,它会启动函数 declaration 或函数 expression.

函数声明在当前函数的范围内声明一个(提升的)局部变量并将该函数分配给该变量。

函数表达式不需要,它们要求您立即对函数做某事。常见示例包括将其分配给对象的 属性,将其作为参数传递给函数(即使其成为回调)或将其用作 IIFE。

如果您尝试使用 () 遵循函数 声明 ,那么它将出错。

function myFunction() {
    console.log("Example");
}();

只有函数表达式可以立即调用函数表达式。 (好吧,箭头函数也可以,但是 IIFE 比它们老得多)。

因此,要使用 IIFE,您必须做 某事 来更改出现 function 关键字的上下文,以便它用于创建表达式而不是声明.

经典的方法是将函数括在括号中。

(function myFunction() {
    console.log("Example");
})();

但是任何使它成为表达式的东西都可以。

将运算符(例如 !+)放在 function 关键字前面即可。

虽然 ! 将采用调用 IIFE 的 return 值并将其转换为否定布尔值,而 + 会将其转换为数字 即重点。运算符的左侧没有任何内容,因此该值被丢弃。

这只是让 function 关键字创建一个函数 expression 的方法,它可以变成一个 IIFE。


请注意,块作用域变量(letconst)和 JavaScript 模块也提供了 IIFE 的主要优点,因此没有太多理由使用2022 年完全没有 IIFE。