【问题标题】:In JavaScript, what is the advantage of !function(){}() over (function () {})()? [duplicate]在 JavaScript 中,!function(){}() 比 (function () {})() 有什么优势? [复制]
【发布时间】:2011-11-27 01:30:45
【问题描述】:

可能重复:
What does the exclamation mark do before the function?

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

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

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

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

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

【问题讨论】:

  • 看这篇文章,它解释了两者之间的区别:stackoverflow.com/questions/3755606/…
  • 我会说这个答案:stackoverflow.com/questions/3755606/…
  • 它们是为此目的(强制在 表达式上下文 中评估函数,立即调用它而忽略其返回值)等效,但恕我直言,我 感觉 i> 使用Grouping Operator(括号)更“语义正确”(可能也更常见和可读),因为这是此运算符的目的,评估表达式...只是我的两分钱...干杯!
  • 我觉得很遗憾这个问题作为副本被关闭了 - 这个问题及其所有答案都比副本中的任何内容都要好。

标签: javascript design-patterns iife


【解决方案1】:

这两种不同的技术具有功能性difference 以及外观差异。一种技术相对于另一种技术的潜在优势将归因于这些差异。

简洁

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

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

  • 普通closure(function(){})() 16 个字符
  • Negatedclosure!function(){}() 15 个字符

这充其量只是一个微优化,所以除非你参加code golf 比赛,否则我认为这不是一个特别有说服力的论点。

否定返回值

比较ab的结果值。

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

由于a 函数不返回任何内容,所以a 将是undefined。因为undefined 的否定是true,所以b 将评估为true。这对于那些想要否定函数的返回值或拥有一切必须返回非空或未定义值的人来说是一个优势。您可以在此 other Stack Overflow question. 上查看有关其工作原理的说明

我希望这可以帮助您理解这个通常被认为是anti-pattern 的函数声明背后的基本原理。

【讨论】:

  • 如果意图只是执行函数(我就是这样使用它的),那么返回 undefined 实际上对我来说更正确。
  • 我给了你一个赞成票,但我在“简洁”方面遇到了一些麻烦......
  • 试图使 Javascript 源代码简洁似乎是造成混乱的秘诀。应该尽可能清楚——这个问题的存在很明显地表明,JS 代码非常需要清晰!它可以通过您在构建过程中引用的缩小器之一传递。
  • @intuited 对。正如我所说,这可能是一个无用的微优化。也就是说,缩小器不会执行此操作,因为它会更改函数的行为并可能导致代码中断。
【解决方案2】:

对于此类问题,我总是求助于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

【讨论】:

  • 哦,很好。我没有看到那个。谢谢!
  • 呃,javascript 是一团糟。
  • JS 不是一团糟,它实际上非常强大——它只是在某些地方有一些不太漂亮的语法。 ;)
  • 所有额外的语法要记住(yes,true,on..do...false..no,false,off),我认为 CoffeeScript 比 Javascript 更复杂。尽管 CoffeeScript 的字符更少,但它并不简单。 gist.github.com/1248911
  • 它确实节省了 1 个字节,但我认为它也可能是一种美学的东西。我不认为! 漂亮,但我认为它比嵌套的((){}()) 结构更丑...
【解决方案3】:

似乎关键是您基本上阻止解析器将函数解释为函数声明,而是将其解释为匿名函数表达式。

使用括号对表达式进行分组或使用 !否定返回都只是改变解析的技术。然后它会立即被以下括号调用。假设没有明确的返回值,所有这些形式在这方面都具有相同的净效应:

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

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

      而且,它少了一个字符。

      【讨论】:

        【解决方案6】:

        在第一种情况下,您使用( ) 将要执行的对象与下一组() 包装在一起,而在下一种情况下,您将使用带有一个参数的运算符(否定运算符!)和你让它用( )隐式包装它的参数(函数)所以你实际上得到!(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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-02-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-01
          • 2012-08-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多