关于javascript:感叹号在函数之前做什么?

What does the exclamation mark do before the function?

1
!function () {}();


javascript语法101。以下是函数声明:

1
function foo() {}

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

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

当然,单是!并不调用函数,但现在我们可以把()放在末尾:!function foo() {}()!优先级高,并立即调用函数。

因此,作者所做的是为每个函数表达式保存一个字节;更易读的编写方法是:

1
(function(){})();

最后,!使表达式返回true。这是因为默认情况下,所有的IIFE都返回undefined,这将使我们得到!undefined,即true。不是特别有用。


功能:

1
function () {}

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

有时我们想在创建函数时正确地调用它。您可能会尝试这样做:

1
function () {}()

但它会导致一个SyntaxError

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

1
!function () {}()

这也将返回与函数返回值相反的布尔值,在这种情况下,true,因为!undefinedtrue。如果希望实际返回值是调用的结果,请尝试这样做:

1
(function () {})()


在airbnb javascript指南中标记的函数调用中使用!是一个很好的方法。

一般来说,在单独的文件(aka模块)上使用这种技术的想法,这些文件随后被连接起来。这里要注意的是,文件应该由工具连接起来,这些工具将新文件放在新行(对于大多数concat工具来说,这无论如何都是常见的行为)。在这种情况下,使用!将有助于避免先前连接的模块遗漏尾随分号时出现的错误,但这将使您能够灵活地将它们按任意顺序排列,而无需担心。

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

工作原理和

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

但保存了两个字符,随意性看起来更好。

通过+-~void操作符在调用函数方面具有相同的效果,当然,如果必须使用某种东西从函数返回,它们的作用会有所不同。

1
2
3
4
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工具进行优化(这使得一行一个文件的工作),那么构造

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

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

这将引发错误,因为JavaScriptASI将无法完成其工作。

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

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

这工作:

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

这不是:

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


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

1
2
3
!false      // true
!true       // false
!isValid()  // is not valid

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

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

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

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

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

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


感叹号使任何函数始终返回布尔值。最后一个值是函数返回值的负数。

1
2
!function bool() { return false; }() // true
!function bool() { return true; }() // false

在上面的例子中省略!是一个语法错误。

1
function bool() { return true; }() // SyntaxError

然而,实现这一目标的更好方法是:

1
(function bool() { return true; })() // true

它只是在我们进行JavaScript缩小时保存一个字节的数据。

考虑下面的匿名函数

1
function (){}

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

1
(function (){}())

现在我们添加了两个额外的字符(,),除了在函数末尾添加(),这是调用函数所必需的。在缩小过程中,我们通常集中精力减小文件大小。所以我们也可以把上面的函数写成

1
!function (){}()

不过,这两个函数都是自调用函数,我们还保存了一个字节。我们使用的不是2个字符(,),而是一个字符!


!是一个逻辑非运算符,它是一个布尔运算符,可以将某些内容转换为相反的内容。

尽管您可以使用bang(!)来绕过被调用函数的括号。在函数之前,它仍然会反转返回,这可能不是您想要的。就像在iefe中一样,它将返回undefined,当inverted变为boolean true时。

Instead, use the closing parenthesis and the BANG (!) if needed.

1
2
3
4
5
6
7
8
9
10
11
12
13
// 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

Other Operators that work...

1
2
3
4
5
6
7
8
+(function(){ return false; }());
=> 0

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

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

Combined Operators...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
+!(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

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

它的另一种写作方式-

1
(function( args ) {})()

等同于

1
!function ( args ) {}();


我们再存几个字节吧!

1
(() => {})()

例子:

1
2
3
4
5
6
(()=>return"是<div class="suo-content">[collapse title=""]<ul><li><wyn>(() => 'yeah')();</wyn></li><li>是的。甚至更好。</li></ul>[/collapse]</div><hr><P><wyn>!</wyn>将否定(相反)你所期望的结果,即如果你有</P>[cc lang="javascript"]var boy = true;
undefined
boy
true
!boy
false

当您调用boy时,您的结果将是true,但当您在调用boy时,即!boy添加!时,您的结果将是false。换言之,你的意思是"Notboy",但这次基本上是一个布尔结果,要么是true,要么是false

这与!function () {}();表达式发生的情况相同,只运行function () {}();将标记错误,但在function () {}();表达式前面添加!,使其与function () {}();表达式相反,后者应返回true。示例如下:

1
2
3
4
function () {}();
SyntaxError: function statement requires a name
!function () {}();
true