叹号在执行功能之前会做什么?

!function () {}();
222991 次浏览

它返回语句是否可以计算为false。例如:

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

你可以使用它两次来强制一个值为boolean:

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

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

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

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

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

其功能:

function () {}

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

有时我们想在创建函数时正确调用它。你可能想试试这个:

function () {}()

但结果是SyntaxError

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

!function () {}()

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

(function () {})()

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

function foo() {}

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

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

当然,单独的!不会调用函数,但我们现在可以将()放在末尾:!function foo() {}(),它比!具有更高的优先级并立即调用函数。

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

所以作者正在做的是为每个函数表达式保存一个字节;更易读的写作方式是这样的:

(function(){})();

最后,!使表达式返回一个基于函数返回值的布尔值。通常,立即调用的函数表达式(IIFE)不会显式返回任何内容,因此它的返回值将是undefined,这给我们留下了!undefined,即true。没有使用这个布尔值。

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

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

在上述示例中省略!将是语法错误

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

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

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

airbnb JavaScript指南上标记的函数调用中使用!是有好处的

通常是在稍后连接的单独文件(又名模块)上使用这种技术的想法。这里需要注意的是,文件应该由将新文件放在新行的工具连接(这是大多数concatat工具的常见行为)。在这种情况下,使用!将有助于避免错误,如果以前连接的模块错过了尾随分号,但这将提供将它们按任何顺序排列的灵活性而不用担心。

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

将与

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

但保存一个字符和任意看起来更好。

顺便说一句,+-~void操作符中的任何一个在调用函数方面都有相同的效果,当然,如果你必须使用一些东西来从该函数返回,它们的行为会不同。

abcval = !function abc(){return true;}() // abcval equals falsebcaval = +function bca(){return true;}() // bcaval equals 1zyxval = -function zyx(){return true;}() // zyxval equals -1xyzval = ~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*/}()

!是一个逻辑不是运算符,它是一个布尔运算符,可以将某些东西反转为它的对立面。

尽管你可以通过在函数之前使用BANG(!)来绕过被调用函数的括号,但它仍然会反转返回,这可能不是你想要的。与IEFE的情况一样,它会返回未定义,当反转时,它将成为布尔值true。

相反,如果需要,请使用右括号和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

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

另一种写作方式——

(function( args ) {})()

!function ( args ) {}();

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

考虑下面的匿名函数:

    function (){}

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

    (function (){}())

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

    !function (){}()

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