在JavaScript中,函数(){}()over(function(){})()的优点是什么?

可能重复:
感叹号在函数之前做了什么?

我很久以前在JavaScript中使用以下自执行匿名函数:

(function () { /* magic happens */ })() 

最近,我开始看到以下模式的更多实例(例如,在Bootstrap中 ):

 !function () { /* presumably the same magic happens */ }() 

任何人都知道第二种模式的优点是什么? 或者,这只是一种文体偏好?

这两种不同的技术在function上有差异,在外观上也有差异。 一种技术相对于另一种技术的潜在优势将归因于这些差异。

简洁

Javascript是一种简洁性非常重要的语言,因为在页面加载时下载 Javascript。 这意味着Javascript越简洁, 下载时间越快 。 出于这个原因,有Javascript压缩器和混淆器压缩Javascript文件,以优化下载时间。 例如, alert ( "Hi" ) ;的空格alert ( "Hi" ) ; 将被优化以alert("Hi");

牢记这一点,比较这两种模式

  • 正常closures 🙁 (function(){})() 16个字符
  • 取消closures!function(){}() 15个字符

这是一个微型优化,所以我不觉得这是一个非常有说服力的论点,除非你正在进行一场高尔夫比赛。

否定返回的值

比较ab的结果值。

 var a = (function(){})() var b = !function(){}() 

由于a函数不返回任何东西,所以a将是undefined 。 由于undefined的否定是trueb将评估为true 。 这对于那些想要否定函数的返回值或具有一切必须返回一个非空值或未定义值的恋物癖的人来说是有利的。 你可以看到这个如何工作的另一个堆栈溢出问题的解释。

我希望这可以帮助你理解这个函数声明的基本原理,通常被认为是反模式 。

对于像这样的问题,我总是回到Ben Alman的IIFE作品上 。 这是我所关心的权威。

这里是文章的肉:

 // 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 

看起来关键的是你基本上保持parsing器不把函数解释为一个函数声明,而是将它解释为一个匿名函数expression式。

使用parens将expression式分组或使用! 否定返回都只是改变parsing的技术。 然后立即由以下parens调用。 假设没有明确的回报价值,所有这些forms在这方面都具有相同的净效应:

 (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 

如果您没有捕获返回值,则没有显着差异。 有人可能会说这个〜可能是一个更快的操作,因为它只是翻转位,或者! 是一个更快的操作,因为它是一个真/假检查和返回否定。

尽pipe如此,大多数人使用这种模式的方式是,他们试图打破一个新的范围,保持干净。 任何和所有的工作。 后面的forms是受欢迎的,因为虽然它们引入了额外的(通常是不必要的)操作,但是节省每个额外的字节有助于。

本·阿尔曼在这个话题上写了一篇精彩的文章: http : //benalman.com/news/2010/11/immediately-invoked-function-expression/

第一个“模式”调用匿名函数(并有其返回值的结果),而第二个“模式”调用匿名函数并取消其结果。

那是你在问什么? 他们这样做。

几乎只是文体偏好,除了事实! 提供了一个函数返回(即返回true ,来自!undefined )。

而且,这是一个较less的字符。

那么在第一种情况下,你正在使用( )来包装你想要执行的对象和下一组() ,在下一个例子中你使用的运算符只有一个参数(否定运算符!),并且你正在隐式地用( )包装它的参数(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