【发布时间】:2011-04-14 21:53:18
【问题描述】:
!function () {}();
【问题讨论】:
-
我们称之为Self-executing anonymous function ---
-
@befzz 最好将其称为立即调用函数表达式,正如该文章稍后解释的那样(“自执行”意味着递归)
标签: javascript function
!function () {}();
【问题讨论】:
标签: javascript function
JavaScript 语法 101。这是一个函数声明:
function foo() {}
注意这里没有分号:这只是一个函数声明。您需要调用 foo() 来实际运行该函数。
现在,当我们添加看似无害的感叹号:!function foo() {} 时,它会将其变成一个表达式。它现在是一个函数表达式。
! 本身当然不会调用该函数,但我们现在可以将 () 放在末尾:!function foo() {}() 的优先级高于 !,并立即调用该函数。
所以作者所做的是为每个函数表达式保存一个字节;一种更易读的写法是这样的:
(function(){})();
最后,! 使表达式返回 true。这是因为默认情况下,所有立即调用的函数表达式 (IIFE) 返回undefined,这给我们留下了!undefined,即true。不是特别有用。
【讨论】:
var foo = 打破了语句/表达式的歧义,您可以简单地写var foo = function(bar){}("baz"); 等。
功能:
function () {}
不返回任何内容(或未定义)。
有时我们想在创建函数时立即调用它。你可能会想试试这个:
function () {}()
但它会导致SyntaxError。
在函数之前使用!运算符会导致它被视为表达式,因此我们可以调用它:
!function () {}()
这也将返回与函数返回值相反的布尔值,在本例中为true,因为!undefined 是true。如果您希望实际返回值是调用的结果,请尝试这样做:
(function () {})()
【讨论】:
! 的目的是将函数声明变成函数表达式,仅此而已。
!function 语法
在airbnb JavaScript guide 上标记的函数调用使用! 有一个好处
一般来说,在单独的文件(也称为模块)上使用这种技术的想法,这些文件后来被连接起来。这里需要注意的是,文件应该由将新文件放在新行的工具连接起来(这对于大多数 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 工具进行优化(这使得一行一文件工作),那么构造
!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 // true
!true // false
!isValid() // is not valid
您可以使用它两次将一个值强制为布尔值:
!!1 // true
!!0 // false
所以,更直接地回答你的问题:
var myVar = !function(){ return false; }(); // myVar contains true
编辑:它具有将函数声明更改为函数表达式的副作用。例如。以下代码无效,因为它被解释为缺少必需的标识符(或函数名称)的函数声明:
function () { return false; }(); // syntax error
【讨论】:
var myVar = !function(){ return false; }() 可以省略!,如var myVar = function(){ return false; }(),该函数将正确执行并且返回值将保持不变。
true 替换为 !0 并将 false 替换为 !1。它可以节省 2 或 3 个字符。
只是为了在我们做 javascript minification 的时候保存一个字节的数据。
考虑下面的匿名函数
function (){}
为了使上面的代码成为自调用函数,我们通常将上面的代码更改为
(function (){}())
现在我们除了在函数末尾添加()之外,还添加了两个额外的字符(,),这是调用函数所必需的。在缩小的过程中,我们一般集中于减小文件大小。所以我们也可以把上面的函数写成
!function (){}()
仍然都是自调用函数,我们也保存了一个字节。而不是 2 个字符 (,) 我们只使用了一个字符 !
【讨论】:
感叹号使任何函数总是返回一个布尔值。
最终值是函数返回值的否定。
!function bool() { return false; }() // true
!function bool() { return true; }() // false
在上述示例中省略 ! 将是 SyntaxError。
function bool() { return true; }() // SyntaxError
但是,实现此目的的更好方法是:
(function bool() { return true; })() // true
【讨论】:
! 改变了运行时解析函数的方式。它使运行时将函数视为函数表达式(而不是声明)。它这样做是为了使开发人员能够使用() 语法立即调用该函数。 ! 也会将自身(即否定)应用于调用函数表达式的结果。
! 是一个逻辑 NOT 运算符,它是一个布尔运算符,可以将某些内容反转为相反的内容。
虽然您可以通过在函数之前使用 BANG (!) 来绕过被调用函数的括号,但它仍然会反转返回,这可能不是您想要的。与 IEFE 的情况一样,它会返回 undefined,它在反转后变为布尔值 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 ) {}();
【讨论】:
(function (args) {...})() 语法,并将!function 形式留给缩小和混淆工具。