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

Javascript 感叹号在函数之前做什么?,javascript,function,Javascript,Function,它返回语句的计算结果是否为false。例如: !function () {}(); 可以使用它两次将值强制为布尔值: !false // true !true // false !isValid() // is not valid 因此,要更直接地回答您的问题: !!1 // true !!0 // false 编辑:它的副作用是将函数声明更改为函数表达式。例如,以下代码无效,因为它被解释为缺少所需标识符(或函数名称)的函数声明: 职能: functio

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

!function () {}();
可以使用它两次将值强制为布尔值:

!false      // true
!true       // false
!isValid()  // is not valid
因此,要更直接地回答您的问题:

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

职能:

function () { return false; }();  // syntax error
不返回任何内容(或未定义)

有时,我们希望在创建函数时正确调用它。您可能会尝试以下方法:

function () {}
但它会导致一个
语法错误

使用
运算符,因此我们可以调用它:

function () {}()
这也将返回与函数返回值相反的布尔值,在本例中为
true
,因为
!未定义的
。如果希望实际返回值是调用的结果,请尝试以下方法:

!function () {}()

JavaScript语法101。下面是一个函数声明

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

(function(){})();
现在,当我们添加看似无害的感叹号时:
!函数foo(){}
将其转换为表达式。它现在是一个函数表达式

!function bool() { return false; }() // true
!function bool() { return true; }() // false
本身并不能调用函数,但我们现在可以将
()
放在末尾:
!函数foo(){}()
,其优先级高于
并立即调用该函数

(function(){})();
因此,作者所做的是为每个函数表达式保存一个字节;更具可读性的书写方式是:

function foo() {}

最后,
使表达式返回true。这是因为默认情况下,所有立即调用的函数表达式(IIFE)都返回未定义的
,这给我们留下了
!未定义
,即
为真
。不是特别有用。

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

(function(){})();
省略
将是一个语法错误

!function bool() { return false; }() // true
!function bool() { return true; }() // false
然而,实现这一目标的更好方法是:

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

使用
有一个很好的理由

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

(function bool() { return true; })() // true
工作原理与

!function abc(){}();
!function bca(){}();
但保存一个字符和任意的外观更好

顺便说一句,
+
-
~
void
操作符中的任何一个在调用函数方面都具有相同的效果,可以肯定的是,如果您必须使用某个东西从该函数返回,它们的行为会有所不同

!function abc(){}();
(function bca(){})();
但如果您使用IIFE模式进行一个文件一个模块的代码分离,并使用concat工具进行优化(这使得一行一个文件工作),那么构建

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?
将执行安全的代码,与第一个代码示例相同

这一个将抛出错误,因为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*/}()

是一个逻辑NOT运算符,它是一个布尔运算符,将某个对象反转为其相反的对象

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

如果需要,请使用右括号和砰(

其他工作人员

组合运算符


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

它的另一种写作方式-

+!(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

(function( args ) {})()

当我们进行javascript缩小时,只需保存一个字节的数据。

考虑下面的匿名函数

!function ( args ) {}();
为了使上面的代码成为自调用函数,我们通常会将上面的代码更改为

function (){}
现在,除了在函数末尾添加调用函数所需的
()
之外,我们还添加了两个额外字符
(,)
。在缩小的过程中,我们通常注重减小文件大小。所以我们也可以把上面的函数写成

(function (){}())

尽管如此,这两个函数都是自调用函数,我们还保存了一个字节。我们只使用了一个字符,而不是两个字符
(,)

这是唯一能解释问题的答案,太棒了!您的第二个代码示例不是有效的JavaScript。
的目的
是将函数声明转换为函数表达式,仅此而已。@Andrey引导程序twitter在所有javascript(jQuery)插件文件中都使用了它。添加此注释以防其他人也有相同的问题。d3.js也使用
!功能
syntax@Andrey-我在最小化代码中看到了这一点,其中保存一个额外字节是一个胜利。+1这是唯一的答案,它实际上解决了为什么要这样做,以及为什么人们看到它使用m
(function (){}())
!function (){}()