关于设计模式:在javascript中,!function(){}() 比 (function () {})()?优点是什么

In JavaScript, what is the advantage of !function(){}() over (function () {})()?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
What does the exclamation mark do before the function?

我长期以来一直使用以下代码来实现JavaScript中的自执行匿名函数:

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

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

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

有人知道第二种模式的优势是什么吗?或者,这只是一种风格偏好?


这两种不同的技术既有功能上的差异,也有外观上的差异。一种技术相对于另一种技术的潜在优势将是由于这些差异。

简洁

Javascript是一种非常重要的语言,因为Javascript是在页面加载时下载的。这意味着JavaScript越简洁,下载时间越快。因此,有一些javascript迷你和模糊器可以压缩javascript文件以优化下载时间。例如,alert ("Hi" ) ;中的空间将优化为alert("Hi");

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

  • 正常关闭:(function(){})()16个字符
  • 反闭包:!function(){}()15个字符

这充其量只是一个微观优化,所以我不认为这是一个特别有说服力的论点,除非你正在进行代码高尔夫比赛。

求反返回值

比较ab的结果值。

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

由于a函数不返回任何内容,因此a将是undefined。由于undefined的否定为trueb将对true进行评价。这对于那些想要否定函数返回值或者拥有"必须返回"非空或"未定义值"狂热的人来说是一个优势。您可以看到关于这个堆栈溢出问题的解释。

我希望这能帮助您理解这个通常被认为是反模式的函数声明背后的基本原理。


对于这样的问题,我总是依赖本·阿尔曼的生活。就我而言,这是决定性的。

这是文章的要点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 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


看起来关键的是,您基本上不让解析器将函数解释为函数声明,而是将其解释为匿名函数表达式。

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

1
2
3
4
5
(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

如果您没有捕获返回的值,则没有显著差异。有人可能会说,~可能是一个更快的操作,因为它只是翻转位,或者可能!是更快的运算,因为它是对/错的检查并返回否定。

然而,在一天结束的时候,大多数人使用这种模式的方式是他们试图打破一个新的范围来保持事物的清洁。任何工作。后一种形式很流行,因为尽管它们引入了一个额外的(通常是不必要的)操作,但是保存每个额外的字节会有所帮助。

本·阿尔曼有一篇关于这个主题的精彩文章:http://ben alman.com/news/2010/11/immediate-invoked-function-expression/


除了!提供函数返回(即返回true,它来自!undefined)之外,它几乎只是风格上的偏好。

另外,它还少了一个字符。


第一个"模式"调用匿名函数(并具有其返回值的结果),而第二个"模式"调用匿名函数并否定其结果。

这就是你要问的吗?他们不做同样的事情。


在第一种情况下,使用( )将要用下一组()执行的对象包装起来,在下一种情况下,使用接受一个参数的运算符(否定运算符!)你让它隐式地用( )包装它的参数(funcion),这样你实际上得到!(function () { })(),执行函数,并否定它返回的结果。这也可以在相同的原则下与-, +, ~一起使用,因为所有这些运算符都采用一个参数。

1
2
3
4
!function () { /* presumably the same magic happens */ }()
-function () { /* presumably the same magic happens */ }()
+function () { /* presumably the same magic happens */ }()
~function () { /* presumably the same magic happens */ }()

你为什么要这么做?我想这是个人偏好,或者如果你有big.js,并且想为每个匿名函数调用保存1个字符…D