感叹号在函数之前做了什么?

!function () {}(); 

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

 function foo() {} 

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

现在,当我们添加看似无害的感叹号时: !function foo() {}将它变成一个expression式 。 现在是一个函数expression式

! 当然,单独不调用这个函数,但是我们现在可以把()放在最后: !function foo() {}() ,它的优先级高于! 并即时调用该函数。

所以作者正在做的是每个函数expression式保存一个字节; 一个更可读的写作方式是:

 (function(){})(); 

最后! 使expression式返回true。 这是因为默认情况下,所有的IIFE返回undefined ,这留下了!undefined这是true 。 不是特别有用。

function:

 function () {} 

没有返回(或未定义)。

有时我们想在创build它时调用一个函数。 你可能会尝试这样做:

 function () {}() 

但是会导致一个SyntaxError

使用! 运算符在函数导致它被视为expression式之前,所以我们可以调用它:

 !function () {}() 

这也将返回函数返回值的布尔值,在这种情况下是true ,因为!undefinedtrue 。 如果你想让实际的返回值成为调用的结果,那就试试这样做:

 (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工具进行优化(这使得一行一个文件作业),比构build

 !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*/}() 

它返回语句是否可以评估为false。 例如:

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

你可以使用它两次强制一个值为布尔值:

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

所以,要更直接地回答你的问题:

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

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

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

这里还有更多我从控制台中弄出来的东西。 如前所述,感叹号使函数返回一个布尔值。

对于后面的一个语法:

 ( function my_function() {} )() 

我们可以做一些事情:

 (function add_them(a,b) { return a+b;} )(9,4) 

就像同时进行的函数定义和调用。

编辑:
现在你会问有什么用'!' types函数定义。 我们来考虑以下几点:

 !function a_would_be_function() { alert("Do some junk but inside a function"); }() 

你会想要执行一个像上面这样的函数,但是没有“!” 会产生一个错误。 希望我清楚。

它是另一种编写IIFE(立即调用函数expression式)的方法。

其他写作方式 –

 (function( args ) {})() 

与…一样

 !function ( args ) {}(); 

是一个逻辑NOT运算符,它是一个布尔运算符,它将相反的东西倒置。

尽pipe可以在函数前面使用BANG (!)来绕过被调用函数的括号,但它仍然会反转返回值,这可能不是您想要的。 就像在IEFE的情况下,它将返回未定义的 ,当反转成为布尔真。

如果需要,请使用右括号和BANG( )。

 // I'm going to leave the closing () in all examples as invoking the function with just ! and () takes away from what's happening. (function(){ return false; }()); => false !(function(){ return false; }()); => true !!(function(){ return false; }()); => false !!!(function(){ return false; }()); => true 

其他运营商的工作…

 +(function(){ return false; }()); => 0 -(function(){ return false; }()); => -0 ~(function(){ return false; }()); => -1 

联合运营商…

 +!(function(){ return false; }()); => 1 -!(function(){ return false; }()); => -1 !+(function(){ return false; }()); => true !-(function(){ return false; }()); => true ~!(function(){ return false; }()); => -2 ~!!(function(){ return false; }()); => -1 +~(function(){ return false; }()); +> -1 

它只是为了保存一个字节的数据,当我们做的JavaScript缩小。

考虑下面的匿名函数

 function (){} 

为了使上面的自我调用function,我们通常会将上面的代码改为

 (function (){}()) 

现在我们在函数的末尾添加了两个额外的字符(,),除了在函数的结尾添加()之外,在缩小的过程中,我们通常集中精力缩小文件的大小。因此,我们也可以把上面的函数写成

 !function (){}() 

仍然都是自我调用function,我们也保存一个字节。而不是2个字符(,),我们只使用一个字符!