【问题标题】:What is the reason for this JavaScript immediate invocation pattern? [duplicate]这种 JavaScript 立即调用模式的原因是什么? [复制]
【发布时间】:2012-01-18 12:30:56
【问题描述】:

我在查看SlickGrid 源代码时遇到了以下模式:

(function ($) {
  var SlickEditor = {

    TextCellEditor: function (args) {
      ...
    },

    LongTextCellEditor: function (args) {
      ...
    }
  };

  $.extend(window, SlickEditor);

})(jQuery);

如果我理解正确的话,它是使用立即调用来定义各种函数对象,然后将它们合并到全局命名空间中。

所以我可以像这样在全局范围内定义我的函数,它会产生相同的效果,对吧?

function TextCellEditor (args) {
  ...
}

function LongTextCellEditor (args) {
  ...
}

我能看到的唯一区别是,在第一个版本中,我可以使用$ 简写来引用jQuery 对象。除此之外,两种情况下的结果都是相同的。

我想知道我是否遗漏了什么。这样做可能还有另一个很好的理由?

更新:请注意,我意识到使用这种立即调用模式允许使用在匿名函数中声明的私有变量。但是在这种情况下没有声明任何变量,并且函数无论如何都被注入到全局范围中。所以我仍然想知道是否有任何真正的区别。

一些答案​​指出,引用局部变量比引用全局变量要快得多。如果我在TextCellEditor() 构造函数中引用$,这是否仍然成立。 $ 并不是 TextCellEditor() 真正的本地,因为它是在外部匿名函数的范围内定义的。

感谢所有 cmets。

【问题讨论】:

  • ... 所示示例将单个变量注入全局范围。您将多个函数注入全局范围。一个全局变量和多个全局变量之间存在巨大差异
  • @Raynos:两个示例都将相同的函数注入全局范围。 $.extend() 调用扩展了具有SlickEditor 的所有属性的窗口对象(在本例中为两个构造函数)。这就是我的问题的重点 - 有什么区别?
  • 哦,等等,我没有意识到 SlickEditor 作者是个白痴,并将所有功能都注入了全局范围。这是一种反模式,两个代码示例都是不好的做法。

标签: javascript jquery design-patterns


【解决方案1】:

不同之处在于,当您使用如您所展示的那样的自调用函数时,您正在为私有变量创建一个局部范围。

这种类型的自调用函数通常称为闭包,是许多 javascript 模式(如模块模式)的基础:http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth

您可以在此处阅读有关 javascript 作用域的更多信息:http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

传入 jQuery 变量的原因有 2 个:

1:通过 $ 调用它更方便,因为它是作为局部变量传入的,我们可以确定 $ 不是别的东西

2:速度更快 - 访问和使用局部变量比全局变量快得多

作为一个例子,看看下面的代码块:

var public_and_global=true;

(function(){
  var private_and_local = true;

  function local_func() {
   //can use private_and_local as well as public_and_global
  }

})();

function global_func() {
   //can only use public_and_global
}

【讨论】:

  • 没有“私有”变量
  • 谢谢马丁。我了解范围/关闭问题。但是由于匿名函数中没有变量,我认为这意味着我的两个示例中的最终结果都是相同的。我不知道性能差异。性能优势是否适用于在 TextCellEditor 构造函数中使用$?我不确定,因为$ 并不是该函数的真正本地,而是外部范围内的匿名函数的本地。
  • 您是对的,在您的确切示例中,最终结果非常接近相同,除了第一个示例中的两个函数在SlickEditor 命名空间内命名。天气与否在确切情况下是性能差异,我将留给您测试:)
  • @Raynos:感谢您的建设性
  • @MartinJespersen 抱歉,但 private_and_local 之类的短语看起来好像“私人”和本地之间没有实际区别。这是一个糟糕的措辞选择。
【解决方案2】:

每个人都将他们的整个代码包装在一个 IIFE 中。

这是因为每个人都使用局部变量,而没有人使用全局变量。

如果您的模块化架构技术恰好是“将模块注入全局范围”,那么您将从您的 IIFE 将模块注入全局范围。

【讨论】:

  • +1 以“每个人都在做...” 同行压力影响开发人员。
  • 感谢您的建议。我知道在这种情况下的最佳做法,但我希望能回答我的具体问题。
【解决方案3】:

是的,在大多数情况下,它会产生相同的效果。但这种方式很好,因为您总是可以使用速记,而且因为不会有变量使全局命名空间变得混乱。假设我有这个扩展,以生成唯一的 id:

var UID = (new Date).getTime();
$.uniqueID = function() { return (UID++).toString(16); }

这会起作用,但是如果我稍后设置UID,可能在另一个脚本中,这个函数将不再起作用。好吧,你永远不能太确定$ 的可用性,这也是一个很好的理由。

在函数内部定义的变量不会存在于全局命名空间中。

【讨论】:

    【解决方案4】:

    当然,马丁所说的。另外:

    所以我可以像这样在全局范围内定义我的函数,它会 效果一样吧?

    没有。这些函数不会在全局名称空间中结束。它们是在本地范围内创建的,然后将对它们的引用提供给 jQuery。全局范围内没有添加任何内容。

    虽然您展示的 sn-p 没有说明这一点,但可以在该范围内定义除函数之外的一些私有数据,例如,固定字符串或查找表,或这些方法可能需要的任何辅助数据,并且函数将可以访问该数据,但是任何其他代码都无法访问该数据(类似于 OO 中的“私有”),该数据也不会污染全局名称空间。

    【讨论】:

    • 我不明白这个。当然$.extend(window, SlickEditor); 行将扩展全局对象(在浏览器的情况下它是窗口对象)。这些函数将可用于任何代码行,而不依赖于 jQuery。
    猜你喜欢
    • 1970-01-01
    • 2019-10-19
    • 1970-01-01
    • 2016-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-09
    • 1970-01-01
    相关资源
    最近更新 更多