【问题标题】:What is this Javascript (function(){})() syntax [duplicate]这是什么Javascript(函数(){})()语法[重复]
【发布时间】:2013-07-15 00:07:36
【问题描述】:

Javascript 中的这种语法到底是什么?我经常看到它被使用(或滥用?):

(function(){})();

我知道它创建了一个匿名函数然后执行它。但是,无法弄清楚为什么必须这样。那不就相当于一种更易读的形式吗:

 function initSomething() {}
 initSomething();

编辑: 感谢所有帮助我理解 Javascript 习语的出色回复。

【问题讨论】:

  • 这是一个立即/自调用函数表达式。
  • (function(){alert("anonymous function!!!")})()
  • @TheNewIdiot,这与混淆无关。
  • 你问它是什么,然后你说你已经知道了。你的问题到底是什么?您是在问为什么人们使用它而不是命名函数?你似乎在你的职位中间换了档。谁说“必须这样”?它没有。如果你想命名一个你永远不会再使用的函数,那就去做吧。

标签: javascript


【解决方案1】:

第二个示例中的函数不再是匿名的......它有一个名称,initSomething

第一种语法通常用于设置闭包...捕获 var x, y, z 以及其中不包含的内容,以便它们不会与闭包之外的任何其他同名变量发生冲突。

【讨论】:

  • 感谢您的简洁回答。
【解决方案2】:

两种方法都可以,但第一种情况是匿名函数(它没有名称,因此可以避免冲突等)。

【讨论】:

    【解决方案3】:

    基本上它是一个未命名(匿名)的函数,一旦加载该函数就会立即执行。

    这种方法的原因是尽可能远离全局范围,并将您的变量与可能在其他地方定义的任何其他变量隔离,您可以在函数内部定义变量和其他函数,它不会垃圾邮件所有这些都在您的全球范围内。

    【讨论】:

      【解决方案4】:

      这是一个自调用的匿名函数。

      function(){} 是一个匿名函数字面量。

      (function(){})() 调用该文字。

      由于这是一个调用自身的匿名函数,所以它是一个自调用的匿名函数。

      第一种形式相对于第二种形式的优势在于它为您提供了一种简单的方法来封装您不想污染全局命名空间的代码。

      您也不必不必要地创建一个函数 initSomething,它现在是全局命名空间的一部分,这可能会破坏其他东西。

      如果您有兴趣了解更多信息,也可以查看here

      【讨论】:

        【解决方案5】:

        这是一个立即调用的函数表达式

        (function(){
          /* code */ 
        }());
        

        取自维基百科,因为它解释得很好。

        立即调用的函数表达式(或 IIFE,发音为“iffy”)是一种 JavaScript 设计模式,它使用 JavaScript 的函数作用域生成词法作用域。立即调用的函数表达式可用于避免从块内提升变量,防止污染全局环境,同时允许公共访问方法,同时保留函数内定义的变量的隐私。

        请参阅here 了解更详细的说明。

        我知道它创建了一个匿名函数然后执行它。但是,无法弄清楚为什么必须这样。那不就相当于一种更易读的形式吗:

        function initSomething() {}
        initSomething();
        

        这不一样,因为initSomething 仍然可以被引用,因此不是匿名的。

        【讨论】:

          【解决方案6】:

          在 JavaScript 中,函数创建了新的作用域。在 JavaScript 的全部内容周围使用函数包装器将确保您永远不会污染全局范围。

          例如,如果您有一个底部带有一些 JavaScript 的 HTML 文件:

          <script>
          var test = 'hello';
          alert(test);          //'hello'
          alert(window.test);   //'hello'
          </script>
          

          如您所见,test 变量实际上变成了 window 对象 (window.test) 的属性,这本质上是 JavaScript 的全局范围。您不想在window 上设置变量的原因有很多,尤其是未来的兼容性问题(如果更高版本的ECMAScript 为window 定义了test 属性怎么办?)。此外,始终使用全局变量很慢,因为每当您使用 test 时,解释器都需要一直沿作用域链向上移动。

          以下在功能上与上面相同,不会污染全局范围。它使用function() 声明一个匿名函数,然后立即使用() 不带参数地调用它。这通常称为立即调用函数表达式或 IIFE

          <script>
          (function() {
              var test = 'hello';
              alert(test);          //'hello'
              alert(window.test);   //undefined
          }());
          </script>
          

          请注意,这只是一个普通的匿名函数,就像任何匿名函数一样。右花括号后的一组括号调用匿名函数。整个事物周围的括号告诉解释器它正在查看一个值或表达式,而不是函数声明。该值只是匿名函数运行时的结果。这使得匿名函数像一个简单的闭包一样工作,程序员可以有效地忽略它。

          此外,您可以对 IIFE 使用两种不同的语法:

          (function() {}());
          (function() {})();
          

          使用任何一个都不太可能出现问题,但是当您的代码中出现一些语法问题时,会出现some differences。 IMO 你最好坚持第一个,这也更清晰易读。

          --

          关于你的第二个问题:以下两个是等价的吗?

          (function(){})();
          

          function initSomething() {}
          initSomething();
          

          呃,好吧,有点。您可能会以同样的方式对待它们而侥幸,因为在大多数情况下,它们的工作方式相同。也就是说,在您的程序中,您将获得与其中任何一个相同的结果(在这两种情况下,您都在定义一个函数,然后调用它)。

          但重要的是要注意匿名函数和函数声明之间的区别。您可以将匿名函数视为可执行文件,或者当您不想定义真正的命名函数时,您可以将其作为胶水传递的代码块。因为它们是匿名的,所以它们不存在于作用域链中,例如,你不能将属性添加到匿名函数对象并在以后使用它们——除非你先将它分配给一个变量,在这种情况下它是不再匿名!

          声明一个函数是完全不同的。它创建了一个构造函数,您可以一次又一次地使用它来创建可以继承原始函数属性的新对象(使用new)。这对很多事情都很有用,尤其是在使用像 AngularJS 这样的框架时。

          function Friend(likes_you) {
              //private property, only accessible to instances of this object
              this.likes_you = likes_you;
          }
          
          //add a function as a property of Friend's prototype -
          //instances of the Friend constructor can call this function
          Friend.prototype.greet = function(greeting) {
              if (this.likes_you) {
                  alert(greeting);
              } else {
                  alert("I don't like you");
              }
          };
          
          var you = new Friend(true);
          you.greet('hello!');          //alerts 'hello!'
          
          var guy = new Friend(false);  //can make as any Friend objects as we want
          guy.greet('hello!');          //alerts "I don't like you"
          

          当然,你不需要做这样的事情,但是了解 JavaScript 真正在做什么是很好的。而这只是 JS 兔子洞的开始……

          【讨论】:

          • 啊,相当于 Python 中的猴子补丁。好的!感谢您的解释。所有其他答案也很好。但我特别喜欢这个结构的对比。我发现具有讽刺意味的一件事是,我看到的大多数使用这个自动执行匿名函数的代码是它们通常有一个注释行来描述它是什么——本质上是一个函数名。那么,如果 () 在 Javascript 中创建了一个作用域,这是否会在不污染全局作用域的同时更具可读性? (函数 initSomething(){})();
          • () 不会在 javascript 中创建范围。 parens 用于对代码进行分组或调用函数(两者都在这里完成)。函数创建范围。匿名函数末尾的() invokes 函数;它不会创建范围。经常看到这种写成(function() {}()); 的包装器。这清楚地表明() 调用函数,而整个函数周围的括号告诉解释器您要生成一个值(即函数运行后的结果),而不是声明函数。
          • 您的最后一个问题对我来说没有意义 - 如果您只想将函数用作范围包装器,则无需命名函数。 (function() {}()); 是声明 IIFE 的最佳方式。为包装函数命名会将该函数添加为全局 window 对象的属性(即污染全局范围),这是您首先要避免的。因此,只需使用上面的包装器并将所有代码放入 {} 中(或者,如果您有多个文件,请将每个文件中的所有代码放入一个包装器中)。
          • 是的,javascript 的原型继承非常类似于 python 中的猴子补丁或任何您可能在语言中找到的“mixins”的一般概念。 js 的对象也与 ruby​​ 非常相似,尽管重要的是要记住 javascript 没有类 - 原型继承的工作方式不同,但可以用来完成许多与其他语言中的类相同的事情
          猜你喜欢
          • 2013-04-12
          • 2016-12-18
          • 2011-10-10
          • 1970-01-01
          • 2013-05-05
          • 1970-01-01
          • 2016-12-28
          • 2010-10-05
          • 2018-10-15
          相关资源
          最近更新 更多