!function () {}();

当前回答

JavaScript语法101:这里是一个函数声明:

function foo() {}

注意没有分号;这只是一个函数声明。您需要调用foo()来实际运行该函数。

现在,当我们添加看似无害的感叹号时:!函数foo(){}将其转换为表达式。现在它是一个函数表达式。

这个当然,单独使用不会调用函数,但我们现在可以将()放在末尾:!函数foo(){}(),其优先级高于!并立即调用该函数。

函数foo(){}()将是一个语法错误,因为不能在函数声明之后立即放置参数(())。

因此,作者正在做的是为每个函数表达式保存一个字节;一种更可读的写作方式是:

(function(){})();

最后一点根据函数的返回值使表达式返回布尔值。通常,立即调用的函数表达式(IIFE)不会显式返回任何内容,因此它的返回值将是未定义的,这就给我们留下了!undefined,这是真的。未使用此布尔值。

其他回答

它返回语句的计算结果是否为false。如:

!false      // true
!true       // false
!isValid()  // is not valid

您可以使用它两次将值强制为布尔值:

!!1    // true
!!0    // false

因此,为了更直接地回答您的问题:

var myVar = !function(){ return false; }();  // myVar contains true

编辑:它的副作用是将函数声明更改为函数表达式。例如,以下代码无效,因为它被解释为缺少所需标识符(或函数名)的函数声明:

function () { return false; }();  // syntax error

当我们进行javascript缩小时,这只是为了保存一个字节的数据。

考虑下面的匿名函数:

    function (){}

为了使上述函数成为自调用函数,我们通常会将上述代码更改为:

    (function (){}())

现在我们添加了两个额外的字符:(和),除了在函数末尾添加()之外,这是调用它所必需的。在缩小过程中,我们通常专注于减小文件大小。因此,我们也可以将上述函数写成:

    !function (){}()

两者仍然是自调用函数,我们也保存了一个字节。我们只使用了一个字符!。

功能:

function () {}

不返回任何内容(或未定义)。

有时我们希望在创建函数时立即调用它。您可能会尝试这样做:

function () {}()

但它会导致SyntaxError。

使用!运算符,使其被视为表达式,因此我们可以调用它:

!function () {}()

这还将返回与函数返回值相反的布尔值,在本例中为true,因为!undefined为true。如果您希望实际的返回值是调用的结果,请尝试这样做:

(function () {})()

这是一个很好的使用点!用于airbnb JavaScript指南上标记的函数调用

一般来说,在单独的文件(也称为模块)上使用这种技术,这些文件稍后会被连接起来。这里需要注意的是,文件应该由将新文件放在新行的工具连接(无论如何,这是大多数concat工具的常见行为)。在这种情况下,使用!将有助于避免错误,如果之前连接的模块遗漏了尾随分号,那么这将提供将它们按任意顺序放置的灵活性,而无需担心。

!function abc(){}();
!function bca(){}();

工作原理与

!function abc(){}();
(function bca(){})();

但是节省了一个字符,而且随意看起来更好。

顺便说一下,在调用函数方面,任何+、-、~、void运算符都有相同的效果,当然,如果必须使用某个函数返回,它们的行为会有所不同。

abcval = !function abc(){return true;}() // abcval equals false
bcaval = +function bca(){return true;}() // bcaval equals 1
zyxval = -function zyx(){return true;}() // zyxval equals -1
xyzval = ~function xyz(){return true;}() // your guess?

但是如果您使用IIFE模式进行一个文件一个模块的代码分离,并使用concat工具进行优化(这使得一行一个文件的工作),那么构建

!function abc(/*no returns*/) {}()
+function bca() {/*no returns*/}()

将执行安全的代码,与第一个代码示例相同。

这将引发错误,导致JavaScript ASI无法执行其工作。

!function abc(/*no returns*/) {}()
(function bca() {/*no returns*/})()

关于一元运算符,需要注意的是,它们会做类似的工作,但仅在情况下,它们不会在第一个模块中使用。因此,如果您不能完全控制连接顺序,它们就不那么安全。

这是有效的:

!function abc(/*no returns*/) {}()
^function bca() {/*no returns*/}()

这不是:

^function abc(/*no returns*/) {}()
!function bca() {/*no returns*/}()

JavaScript语法101:这里是一个函数声明:

function foo() {}

注意没有分号;这只是一个函数声明。您需要调用foo()来实际运行该函数。

现在,当我们添加看似无害的感叹号时:!函数foo(){}将其转换为表达式。现在它是一个函数表达式。

这个当然,单独使用不会调用函数,但我们现在可以将()放在末尾:!函数foo(){}(),其优先级高于!并立即调用该函数。

函数foo(){}()将是一个语法错误,因为不能在函数声明之后立即放置参数(())。

因此,作者正在做的是为每个函数表达式保存一个字节;一种更可读的写作方式是:

(function(){})();

最后一点根据函数的返回值使表达式返回布尔值。通常,立即调用的函数表达式(IIFE)不会显式返回任何内容,因此它的返回值将是未定义的,这就给我们留下了!undefined,这是真的。未使用此布尔值。