【问题标题】:What is this practice called in JavaScript?这种做法在 JavaScript 中叫什么?
【发布时间】:2011-04-12 19:50:51
【问题描述】:

当您将 JavaScript 代码包装在这样的函数中时:

(function(){

  var field = ...;
  function doSomthing(){...
  ...


})();

我注意到这解决了我在很多网页上的范围界定问题。这种做法叫什么?

【问题讨论】:

  • 可能,但我对实践的名称感兴趣,而不是对机制的影响和理解,我相信另一个问题与此有关。
  • 是的,你是对的,我也注意到了,就在我点击按钮之后。
  • 这是一个关于parens与IE交互的完全不同的问题,而不是关于上述做法的所谓
  • @DanMan...完全一样。 Crockford 恰好喜欢“inside”上的“calling”括号。这只是个人偏好(我实际上同意 Crockford 对此的偏好)。
  • @stevebot:基本上是同一个问题。它的特点是用正确的(并且现在被广泛采用的)术语“立即调用的函数表达式”提供了一个好的 - 更好的答案。即使您考虑接受 DavidMurdoch 的回答,该线程似乎也缺乏这样的内容。问题被关闭是基于答案的质量,而不是被问到的时间 - 不要觉得被冒犯了,你应该得到 50 个赞成票。

标签: javascript design-patterns terminology iife


【解决方案1】:

为了澄清一下下面的 cmets,大多数它在创建 闭包 时,它会将您的变量范围限定为该本地闭包,以免创建全局变量,它既可以保持干净,又可以避免对这些变量进行任何潜在的不必要的更改。

这里有一些很好的答案可以解释为什么更多一点:How does a javascript closure work?

它只是一个 creating 闭包,当该范围内的某些东西暴露给外部范围时,通常就是这种情况,但我不能确定你的例子没有看到更多的代码。如果没有公开任何内容,则不会创建任何闭包......否则它只是一个立即执行的匿名函数。

最后的})(); 格式,而不是});,实际上是调用闭包立即执行,没有参数。如果你有一些东西,例如})(something);,那么something将作为第一个参数传递:(function(somethingParam){

【讨论】:

  • 严格来说,闭包是函数的副作用。这不是闭包,而是一个函数。事实上,在这种情况下甚至可能没有创建闭包,因为无法从外部访问函数的内容。见jibbering.com/faq/notes/closures
  • @Jani - 这就是闭包的作用......它专门用于(在这种情况下)从外部隐藏内容,同时让它们可以访问内部的任何东西。甚至您提供的链接也给出了这个 exact 定义:“闭包的简单解释是 ECMAScript 允许内部函数;函数定义和函数表达式位于其他函数的函数范围内。而那些内部允许函数访问其外部函数中的所有局部变量、参数和声明的内部函数。"
  • @Nick,您引用的行是指标识符解析过程的工作方式,而不是专门针对闭包的形成,继续引用:“A closure当这些内部函数之一在包含它的函数之外可以访问时形成,因此它可以在外部函数返回后执行。”因此,如果没有 inner 函数可供外部使用,则闭包 not 形成-@Jani 指出-,IMO 术语 closure现在有时会被过度使用。
  • @Nick,是的,这个例子不完整。是的,您几乎总是将某些东西暴露给外部,在 function(或包含引用本地函数的属性的对象)的情况下,形成了一个闭包。感谢您的澄清。
  • @Nick:函数不是闭包。不要混淆你的术语。闭包是函数共享的变量。一个函数可以创建一个闭包,但它本身并不是一个闭包。这就像称烤箱为蛋糕一样。蛋糕不是烤箱,但烤箱可以用来烤蛋糕。
【解决方案2】:

包装函数称为匿名(它没有名称,也没有分配给变量)自执行(它自己立即执行)函数。

我不记得看到此模式的确切名称,但它可以防止变量泄漏到全局范围内。

【讨论】:

  • 我个人称它为自调用函数。当我说出这句话时,大多数经验丰富的 javascript 开发人员都知道我在说什么。
  • 我称之为匿名作用域函数
  • 它不会调用自己。该函数恰好被立即调用。没有递归进行,没有“自执行”。
【解决方案3】:

该模式称为self-invocation,一个self-invoking function。它可以创建一个闭包,但这是模式的效果(可能是预期的效果),而不是模式本身。

【讨论】:

  • 我不知道你怎么把它称为副作用......如果你想立即执行代码(并且 不是 闭包)为什么将它包装在首先发挥作用?这是一种直接而有意的效果。
  • @Nick Craver:见编辑。我的意思是效果,但预期的效果。
  • @Nick:闭包是一种可能的副作用。函数不是闭包。没有名称的函数称为匿名函数,不熟悉函数式语言的人错误地将其称为闭包。在javascript中,大括号(..)中声明的东西是表达式,所以这是一个匿名函数表达式。所有的表达式都会返回一些东西。在函数表达式的情况下,它返回对函数的引用。以上这些都不是传统意义上的闭包。闭包是函数之间共享的变量,而不是函数本身。
  • @slebetman - 你没有阅读上面的 cmets,或者我在 20 分钟前更新的答案,我明确地澄清了这一点:“当该范围内的某些东西暴露于外部范围时,这只是一个闭包,通常是这种情况,但是如果没有看到更多代码,我无法确定您的示例。如果没有公开任何内容,则不会创建任何闭包......否则它只是一个立即执行的匿名函数。”
  • @Nick:即便如此,它也不是一个闭包,而是一个匿名函数。尽管闭包依赖于函数,但这两个概念是分开的。
【解决方案4】:

Douglas Crockford 和 YUI 团队称之为 the module pattern

【讨论】:

  • 模块模式比这更具体。它使用“闭包”作为向初始(立即)调用时返回的对象或函数提供私有方法和变量的一种方式。
  • 所以它只有在返回一个对象时才算作一个模块(可能私有状态隐藏在局部变量中)?太糟糕了。
【解决方案5】:

Ben Alman 就该“模式”的常用术语提出了一个有趣的论点。

他的博文是here (http://benalman.com/news/2010/11/immediately-invoked-function-expression/)

如果他的帖子对你来说太长,这里是我的摘要(我仍然建议阅读它,因为这个摘要遗漏了很多):

如果您希望一个命名函数能够自我执行/调用,它应该如下所示:

// Hello, my name is "foo". I am a named function.
// When I am invoked I invoke my self when I am invoked.
function foo(){
   foo();
}

如果您希望匿名函数能够自我执行/调用,它应该如下所示:

// Hello, I have no name...
//   (though I am assigned to the variable "foo" it's not who I am).
// When I am invoked I invoke my self when I am invoked.
// In ECMAScript 5 I no longer work. :-(
var foo = function(){
    arguments.callee();
};

如果您希望立即执行/调用匿名函数,它应该如下所示:

// Hello, I have no name. I am immediately invoked.
// People sometimes call me a "self-invoking anonymous function"...
//    even though I don't invoke myself.
// Ben Alman calls me an "Immediately-Invoked Function Expression"...
//    or "iffy" for short.
(function(){ /...code.../ }());

我对此事的看法:

其他答案都是正确的;您所询问的内容通常被称为“自调用匿名函数”。
但是,该术语并不能准确反映实际发生的情况。 “立即调用函数表达式”(简称“iffy”)似乎是一个更合适的术语。


有趣的事实给你的朋友留下深刻印象:

你也可以像这样创建一个 IFFY:

!function(){
   alert("immediately invoked!");
}();

+function(){
   alert("immediately invoked!");
}();

或者如果你是真的疯狂(example):

!1%-+~function(){
   alert("immediately invoked!");
}();

在大多数浏览器中(如果不是全部,我不确定),效果是一样的(facebook 使用! 版本)。

【讨论】:

  • 我不建议使用那些“快捷方式”,因为大多数开发人员对此一无所知,而且我不确定浏览器的兼容性。跨浏览器测试它,如果它在任何地方都能正常工作,你总是可以这样做:!(function(){}()); 所以你仍然可以使用漂亮的! 和广为人知的“立即调用函数表达式”。
【解决方案6】:

它的存在时间比“模式”还要久。它是 scheme/lisp 中的一个常见习语,主要用于封装,尤其是在进行元编程时。

【讨论】:

  • 简单示例:((lambda () (let ((foo (lambda () (+ 1 1)))) (foo))))
【解决方案7】:

这种做法叫什么?

它被称为immediately-invoked function expression,简称:IIFE。它在表达式中定义了一个函数,然后它自己执行(不将函数分配给任何标识符)。有时也称为立即执行函数表达式(IEFE)。

在 Ben Alman 写关于它们的博客文章之前,它们也被称为 自调用(匿名)函数,从那时起这个术语就变得不常见了。这在技术上是不精确的,暗示了一个实际上并没有发生的递归调用。

有关语法的详细信息,请参阅Explain the encapsulated anonymous function syntaxLocation of parenthesis for auto-executing anonymous JavaScript functions?

我注意到这解决了我在很多网页上的范围界定问题。

是的,the purpose of this pattern 是通过执行一个函数来引入一个额外的作用域。

该模式有时也扩展为返回值,称为 (显示)模块模式,或使用函数名称以允许递归调用。

【讨论】:

    猜你喜欢
    • 2017-09-09
    • 1970-01-01
    • 2011-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多