可能重复:
What does the exclamation mark do before the function?
我长期以来在JavaScript中使用以下自动执行的匿名函数:
(function () { /* magic happens */ })()
最近,我开始看到以下模式的更多实例(例如,在Bootstrap中):
!function () { /* presumably the same magic happens */ }()
任何人都知道第二种模式的优势是什么?或者,这只是一种风格偏好吗?
答案 0 :(得分:79)
这两种不同的技术具有功能性difference以及外观上的差异。一种技术相对于另一种技术的潜在优势将归因于这些差异。
Javascript是一种语言,其中简洁非常重要,因为当页面加载时,会下载。这意味着Javascript越简洁,下载时间越快。因此,有Javascript minifiers和obfuscators压缩Javascript文件以优化下载时间。例如,alert ( "Hi" ) ;
中的空格将优化为alert("Hi");
。
记住这一点,比较这两种模式
这是一个微观优化,所以除非你进行code golf比赛,否则我认为这不是一个特别引人注目的论点。
比较a
和b
的结果值。
var a = (function(){})()
var b = !function(){}()
由于a
函数未返回任何内容,a
将为undefined
。由于undefined
的否定为true
,b
将评估为true
。对于想要否定函数的返回值或者具有一切 - 必须返回非null或未定义值的迷信的人来说,这是一个优势。您可以在此other Stack Overflow question.
我希望这有助于您了解此函数声明背后的基本原理,通常会将其视为anti-pattern。
答案 1 :(得分:51)
对于这样的问题,我总是回到Ben Alman's IIFE piece。就我而言,它是决定性的。
以下是the article的内容:
// 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
答案 2 :(得分:14)
似乎关键在于你基本上不让解析器将函数解释为函数声明,而是将其解释为匿名函数表达式。
使用parens对表达式进行分组或使用!否定返回只是改变解析的技巧。然后由以下的parens立即调用它。假设没有明确的回报值,任何和所有这些形式在这方面具有相同的净效应:
(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/
答案 3 :(得分:4)
第一个“模式”调用匿名函数(并具有其返回值的结果),而第二个调用匿名函数并否定其结果。
这就是你问的问题吗?他们不做同样的事情。
答案 4 :(得分:4)
除了!
提供函数返回(即返回来自true
的{{1}})之外,几乎只有风格偏好。
此外,它只少了一个角色。
答案 5 :(得分:1)
在第一种情况下,您使用( )
将要执行的对象与下一组()
包装在一起,在下一种情况下,您使用的是带有一个参数的运算符(否定)运算符!)并且你正在使用( )
隐式包装它的参数(funcion),这样你实际得到!(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