感叹号在函数之前做了什么?
!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
,因为!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工具进行优化(这使得一行一个文件作业),比构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个字符(,),我们只使用一个字符!