What does the exclamation mark do before the function?
1 | !function () {}(); |
javascript语法101。以下是函数声明:
1 | function foo() {} |
注意,这里没有分号:这只是一个函数声明。您需要一个调用,
现在,当我们加上看似无害的感叹号:
当然,单是
因此,作者所做的是为每个函数表达式保存一个字节;更易读的编写方法是:
1 | (function(){})(); |
最后,
功能:
1 | function () {} |
不返回任何内容(或未定义)。
有时我们想在创建函数时正确地调用它。您可能会尝试这样做:
1 | function () {}() |
但它会导致一个
在函数使其被视为表达式之前使用
1 | !function () {}() |
这也将返回与函数返回值相反的布尔值,在这种情况下,
1 | (function () {})() |
在airbnb javascript指南中标记的函数调用中使用
一般来说,在单独的文件(aka模块)上使用这种技术的想法,这些文件随后被连接起来。这里要注意的是,文件应该由工具连接起来,这些工具将新文件放在新行(对于大多数concat工具来说,这无论如何都是常见的行为)。在这种情况下,使用
1 2 | !function abc(){}(); !function bca(){}(); |
工作原理和
1 2 | !function abc(){}(); (function bca(){})(); |
但保存了两个字符,随意性看起来更好。
通过
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 |
当您调用
这与
1 2 3 4 | function () {}(); SyntaxError: function statement requires a name !function () {}(); true |