4

我已经阅读了 10 篇关于闭包的 SO 参考资料、MDN 参考资料和其他博客文章。他们似乎都以自己的方式定义了闭包。例如,来自 MDN 文档:

function makeFunc() {
  var name = "Mozilla";
  function displayName() {
    alert(name);
  }
  return displayName;
}

var myFunc = makeFunc();
myFunc();

这是他们对关闭的解释:

通常,函数中的局部变量仅在该函数执行期间存在。一旦 makeFunc() 完成执行,可以合理地预期 name 变量将不再可访问。由于代码仍然按预期工作,显然情况并非如此。

这个难题的解决方案是 myFunc 已经变成了一个闭包。闭包是一种特殊的对象,它结合了两件事:一个函数,以及创建该函数的环境。环境由创建闭包时在范围内的任何局部变量组成。在这种情况下,myFunc 是一个闭包,它包含了 displayName 函数和创建闭包时存在的“Mozilla”字符串。

下面的 StackOverflow 帖子将闭包回答为一堆可见范围。 Javascript 中存在哪些类型的范围?

我感到困惑的地方:闭包是一个对象吗?或者它只是一个“异常范围情况”,其中内部嵌套函数可以访问在其外部定义但对容器父函数本地的变量,即使在父函数已经执行之后?闭包是引用这种嵌套函数(范围)情况的对象myFunc还是内部函数本身?

4

3 回答 3

2

简而言之,

另一个函数内部的函数可以访问外部函数中声明的变量。如果函数在全局上下文中,它显然可以访问全局变量。

更多背景:

var v1; // I'm accessible anywhere    
function a() {
    var v2;
    function b() { // I can access v2 and v1
        var v3;
        function c() {  // I can access v1, v2, v3
            var v4;
        }
        return c;
    }
    return b();
}
var f = a();

在上面,a, b,c都是闭包,它们可以访问它们各自的父作用域,并且递归地进行直到window或全局上下文。


一般来说,每个函数都是一个闭包。但是我们只想到它们,当我们实现一些实际上依赖于闭包的东西时,比如工厂函数。

于 2015-01-29T16:55:52.993 回答
1

你可以把 JS 函数想象成这样的结构:

class Function : Object {
  bytes      bytecode;
  varframe   varsAndArgs;
}

class varframe{
  array<value>  values;
  ptr<varframe> parent;
}

所以 JS 中的每个函数实例在技术上都是一个闭包。在顶级函数中,父指针为空。

所以当你定义

function makeFunc() {
  var name = "Mozilla";
  function displayName() {
    alert(name);
  }
  return displayName;
}

该 displayName (const/variable) 将包含类 Function 的实例,该实例将包含对该结构自己的 varframe 的引用:

varframe(displayName) 
  values[0] // empty array, no variables in it
  parent -> varframe(makeFunc) 
              values[1] // one variable "name" at index 0;
              parent = null    

因此闭包是一个结构,它持有对代码的引用和对 varframes 链(又名 callframes)的引用。

于 2015-01-29T17:30:13.727 回答
0

过去,很多课程材料和参考资料有时都强调 JavaScript 的 OO 方面而忽略了函数式方法。我认为随着框架的发展和大量 JS 库的收集,这种情况开始发生变化。JavaScript Ninja的秘密证明了掌握函数是有效使用 JavaScript 的基本部分。在Ninja中,闭包的定义更为笼统:

“...闭包允许函数访问所有变量,以及声明函数本身时范围内的其他函数。”

                                         -- "Chapter 5: Closing in on closures"

讨论闭包时,Effective JavaScript(或多或少)是这样说的:

  • 函数可以引用在其范围之外定义的变量;
  • 在第二个函数返回后,函数可以引用另一个函数定义的变量(因为在 JavaScript 中函数是对象);
  • 函数可以包含“封闭”的内部函数,并且可以修改封闭函数的属性。

有效 JavaScript 第 2 章的源代码。第 11 项“熟悉闭包”在 gibhub 上:

封闭函数的巧妙之处在于,如果您不打算显式调用它,它就不需要名称:它可以是匿名的,并且可以简单地作为外部函数的一部分进行评估。

于 2015-01-29T17:13:50.840 回答