可能重复:
在函数前面加上感叹号(!)是什么意思?
我长期以来都在JavaScript中使用以下代码来创建自执行的匿名函数:
(function () { /* magic happens */ })()
最近,我开始看到更多以下模式的实例(例如,在Bootstrap中):
!function () { /* presumably the same magic happens */ }()
有人知道第二种模式的优点是什么吗?或者,这只是一种风格偏好吗?
可能重复:
在函数前面加上感叹号(!)是什么意思?
我长期以来都在JavaScript中使用以下代码来创建自执行的匿名函数:
(function () { /* magic happens */ })()
最近,我开始看到更多以下模式的实例(例如,在Bootstrap中):
!function () { /* presumably the same magic happens */ }()
有人知道第二种模式的优点是什么吗?或者,这只是一种风格偏好吗?
这两种不同的技术在功能上有所区别, 外观也不同。其中一种技术优于另一种的潜在优点将源于这些差异。
Javascript是一种语言,简洁性非常重要,因为Javascript是在页面加载时下载的。这意味着Javascript越简洁,下载时间就越快。出于这个原因,有Javascript 压缩器 和 混淆器 可以压缩Javascript文件以优化下载时间。例如,alert ( "Hi" ) ;
中的空格将被优化为 alert("Hi");
。
记住这一点,比较这两种模式:
这只是一个微小的优化,除非你在进行代码高尔夫比赛,否则我不认为这是一个特别有说服力的论点。比较a
和b
的结果值。
var a = (function(){})()
var b = !function(){}()
a
没有返回任何值,因此 a
将会是 undefined
。由于对 undefined
的否定是 true
,b
将被评估为 true
。这对那些想要否定函数返回值或者有一个“一切都必须返回非空或未定义值”的迷恋的人来说是一个优势。您可以在 其他Stack Overflow问题 上查看这种工作方式的解释。undefined
实际上对我来说更加正确。 - Andrew Hedges// Either of the following two patterns can be used to immediately invoke
// a function expression, utilizing the function's execution context to
// create "privacy."
(function(){ /* code */ }()); // Crockford recommends this one
(function(){ /* code */ })(); // But this one works just as well
// Because the point of the parens or coercing operators is to disambiguate
// between function expressions and function declarations, they can be
// omitted when the parser already expects an expression (but please see the
// "important note" below).
var i = function(){ return 10; }();
true && function(){ /* code */ }();
0, function(){ /* code */ }();
// If you don't care about the return value, or the possibility of making
// your code slightly harder to read, you can save a byte by just prefixing
// the function with a unary operator.
!function(){ /* code */ }();
~function(){ /* code */ }();
-function(){ /* code */ }();
+function(){ /* code */ }();
// Here's another variation, from @kuvos - I'm not sure of the performance
// implications, if any, of using the `new` keyword, but it works.
// http://twitter.com/kuvos/status/18209252090847232
new function(){ /* code */ }
new function(){ /* code */ }() // Only need parens if passing arguments
!
很好看,但我认为它比嵌套的 ((){}())
结构要少一些丑陋感。 - Chris Burt-Brown看起来关键的是,你基本上是防止解析器将函数解释为函数声明,而是将其解释为匿名函数表达式。
使用括号来分组表达式或使用!来否定返回值都只是改变解析的技巧。然后立即通过以下括号调用它。在这方面,任何一个形式都具有相同的净效应,假设没有显式返回值:
(function(){ /* ... */ })(); // Arguably most common form, => undefined
(function(){ /* ... */ }()); // Crockford-approved version, => undefined
!function(){ /* ... */ }(); // Negates the return, so => true
+function(){ /* ... */ }(); // Attempts numeric conversion of undefined, => NaN
~function(){ /* ... */ }(); // Bitwise NOT, => -1
如果您没有捕获返回值,那么没有什么重大的区别。有人可能会认为 ~ 可能是一个更快的操作,因为它只是翻转位,或者 ! 是一个更快的操作,因为它是一个真/假检查并返回否定。
然而,大多数人使用此模式的方式是尝试打破一个新的作用域级别以保持清洁。所有形式都可以使用。后一种形式很受欢迎,因为它们引入了一个额外的(通常是不必要的)操作,但节省每个额外的字节都有帮助。
Ben Alman在这个主题上有一个很棒的介绍:http://benalman.com/news/2010/11/immediately-invoked-function-expression/
第一个“模式”调用匿名函数(并具有其返回值的结果),而第二个则调用匿名函数并否定其结果。
这就是你在问什么吗?它们不做相同的事情。
这几乎只是样式上的偏好,除了 !
提供函数返回(即返回 true
,来自于 !undefined
)之外。
此外,它少一个字符。
在第一个案例中,您使用( )
来包装您想要执行的对象以及下一组()
,而在下一个案例中,您使用一个接受一个参数的运算符(否定运算符!),并且您使其隐式地用( )
括起其参数(函数),因此您实际上得到!(function(){}())
,执行函数并否定它返回的结果。这也可以使用相同的原则用于-、+、~
,因为所有这些运算符都只接受一个参数。
!function () { /* presumably the same magic happens */ }()
-function () { /* presumably the same magic happens */ }()
+function () { /* presumably the same magic happens */ }()
~function () { /* presumably the same magic happens */ }()
为什么你想要这样做呢?我猜这是个人喜好,或者如果你有一个很大的 .JS 文件并且想要在每个匿名函数调用中节省 1 个字符... :D