首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JavaScript闭包在哪里?

JavaScript闭包在哪里?
EN

Stack Overflow用户
提问于 2016-05-27 20:18:00
回答 5查看 2.1K关注 0票数 29

我编写这段代码是为了教会自己有关JavaScript闭包的知识:

代码语言:javascript
复制
function1 = function(){
  var variable = "foo"
  var function2 = function(argument){
    console.log(variable + argument);
  }
  return function2
}

function3 = function1();
function3("bar");

这印出了预期的"foobar“。但是变量在哪里呢?

它是function3的一个属性,还是存储在function3中的其他地方?JavaScript是否遍历某种闭包链,类似于它如何遍历原型链?它是不是储存在其他地方的记忆里?

我正试图更深入地理解这一点。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2016-05-27 22:24:38

tl;dr:

变量在哪里?

在环境中它被定义为。

它是function3的一个属性,还是存储在function3中的其他地方?

不是的。

JavaScript是否遍历某种闭包链,类似于它如何遍历原型链?

是。

它是不是储存在其他地方的记忆里?

是。

tl;dr 2:

函数保持对在其中创建的环境的引用。当一个函数被调用时,它会创建一个新的环境,其父环境是该函数保持引用的环境。

更长的解释:

每当执行一个函数时,都会创建一个新的词汇环境。该环境有两个“字段”:一个跟踪所有变量的http://www.ecma-international.org/ecma-262/6.0/index.html#sec-environment-records和一个引用“父词法环境”的外部词汇环境(顾名思义)。

因此,在计算代码示例时,内存的初始状态(在执行任何操作之前)可能如下(简化):

代码语言:javascript
复制
+-(Global) lexical environment-+     +-Environment Record-+
+-------------+----------------+     +---------+----------+
| Environment |       *--------+---> |function1|undefined |
|   Record    |                |     +---------+----------+
+-------------+----------------+     |function3|undefined |
|    Outer    |                |     +---------+----------+
|   lexical   |    (empty)     |
| environment |                |
+-------------+----------------+

全球环境没有任何外部环境,因为它在顶部。function1function3是两个尚未初始化的绑定(赋值尚未评估)。

在创建函数(评估function1 = function() { ... })之后,内存如下所示:

代码语言:javascript
复制
            +------------------------------------------------------------------------+
            |                                                                        |
            v                                                                        |
+-(Global) lexical environment-+    +-Environment Record-+     +-----Function Object-+---+
+-------------+----------------+    +---------+----------+     +---------------+-----+---+
| Environment |       *--------+--->|function1|    *-----+---->|[[Environment]]|     *   |
|   Record    |                |    +---------+----------+     +---------------+---------+
+-------------+----------------+    |function3|undefined |     |     name      |function1|
|    Outer    |                |    +---------+----------+     +---------------+---------+
|   lexical   |    (empty)     |
| environment |                |
+-------------+----------------+

现在,function1有一个值,一个函数对象。函数对象具有多个内部(例如[[Environment]])和外部(例如name)属性。顾名思义,内部属性不能从用户代码中访问。[[Environment]]属性非常重要。注意它是如何引用创建函数的词法环境的!

下一步是执行function3 = function1(),即调用function2。正如我在一开始所说的,每当函数被执行时,都会创建一个新的词法环境。让我们看一下在输入函数之后的内存:

代码语言:javascript
复制
               +------------------------------------------------------------------------+
               |                                                                        |
               v                                                                        |
   +-(Global) lexical environment-+    +-Environment Record-+     +-----Function Object-+---+
   +-------------+----------------+    +---------+----------+     +---------------+-----+---+
   | Environment |       *--------+--->|function1|          +---->|[[Environment]]|     *   |
   |   Record    |                |    +---------+----------+     +---------------+---------+
+> +-------------+----------------+    |function3|undefined |     |     name      |function1|
|  |    Outer    |                |    +---------+----------+     +---------------+---------+
|  |   lexical   |    (empty)     |
|  | environment |                |
|  +-------------+----------------+
|
|
|
|  +-----lexical environment------+    +-Environment Record-+
|  +-------------+----------------+    +---------+----------+
|  | Environment |       *--------+--->|variable |undefined |
|  |   Record    |                |    +---------+----------+
|  +-------------+----------------+    |function2|undefined |
|  |    Outer    |                |    +---------+----------+
|  |   lexical   |        *       |
|  | environment |        |       |
|  +-------------+--------+-------+
|                         |
+-------------------------+

这看起来非常类似于全球环境的结构!我们有一个词汇环境,它有一个环境记录,有两个未合并的绑定。但现在最大的不同是“外部词汇环境”指向了全球词汇环境。那件事怎么可能?

在调用function1并创建新的词法环境时,我们将新环境“外部词汇环境”字段的值设置为function1[[Environment]]字段的值,即创建范围链。

现在,在执行function1之后,内存具有以下结构:

代码语言:javascript
复制
               +------------------------------------------------------------------------+
               |                                                                        |
               v                                                                        |
   +-(Global) lexical environment-+    +-Environment Record-+     +-----Function Object-+---+
   +-------------+----------------+    +---------+----------+     +---------------+-----+---+
   | Environment |       *--------+--->|function1|    *-----+---->|[[Environment]]|     *   |
   |   Record    |                |    +---------+----------+     +---------------+---------+
+> +-------------+----------------+    |function3|   |      |     |     name      |function1|
|  |    Outer    |                |    +---------+---+------+     +---------------+---------+
|  |   lexical   |    (empty)     |                  |
|  | environment |                |                  |
|  +-------------+----------------+                  +-------------------------+
|                                                                              |
|             +----------------------------------------------------------------+--------+
|             v                                                                |        |
|  +-----lexical environment------+    +-Environment Record-+                  v        |
|  +-------------+----------------+    +---------+----------+                           |
|  | Environment |       *--------+--->|variable |  'foo'   |     +-----Function Object-+---+
|  |   Record    |                |    +---------+----------+     +---------------+-----+---+
|  +-------------+----------------+    |function2|    *-----+---->|[[Environment]]|     *   |
|  |    Outer    |                |    +---------+----------+     +---------------+---------+
|  |   lexical   |        *       |                               |     name      |function2|
|  | environment |        |       |                               +---------------+---------+
|  +-------------+--------+-------+
|                         |
+-------------------------+

类似于function1function2有一个通过调用function2创建的环境的引用。此外,function3引用我们创建的函数,因为我们从function1返回它。

最后一步:调用function3('bar')

代码语言:javascript
复制
               +------------------------------------------------------------------------+
               |                                                                        |
               v                                                                        |
   +-(Global) lexical environment-+    +-Environment Record-+     +-----Function Object-+---+
   +-------------+----------------+    +---------+----------+     +---------------+-----+---+
   | Environment |       *--------+--->|function1|    *-----+---->|[[Environment]]|     *   |
   |   Record    |                |    +---------+----------+     +---------------+---------+
+> +-------------+----------------+    |function3|   |      |     |     name      |function1|
|  |    Outer    |                |    +---------+---+------+     +---------------+---------+
|  |   lexical   |    (empty)     |                  |
|  | environment |                |                  |
|  +-------------+----------------+                  +-------------------------+
|                                                                              |
|             +----------------------------------------------------------------+--------+
|             v                                                                |        |
|  +-----lexical environment------+    +-Environment Record-+                  v        |
|  +-------------+----------------+    +---------+----------+                           |
|  | Environment |       *--------+--->|variable |  'foo'   |     +-----Function Object-+---+
|  |   Record    |                |    +---------+----------+     +---------------+-----+---+
|+>+-------------+----------------+    |function2|    *-----+---->|[[Environment]]|     *   |
|| |    Outer    |                |    +---------+----------+     +---------------+---------+
|| |   lexical   |        *       |                               |     name      |function2|
|| | environment |        |       |                               +---------------+---------+
|| +-------------+--------+-------+
++------------------------+
 |
 | +-----lexical environment------+    +-Environment Record-+
 | +-------------+----------------+    +---------+----------+
 | | Environment |       *--------+--->|argument |  'bar'   |
 | |   Record    |                |    +---------+----------+
 | +-------------+----------------+
 | |    Outer    |                |
 | |   lexical   |        *       |
 | | environment |        |       |
 | +-------------+--------+-------+
 +------------------------+

类似于这里,创建了一个新的环境,它的“外部词法环境”字段指向调用function1时创建的环境。

现在,查找argument的值很简单,因为它存在于环境自己的记录中。但是当查找variable时,会发生以下情况:由于它不存在于环境本身的记录中,它会查看它的“外部词法环境”的记录,因为它有一个引用。

票数 39
EN

Stack Overflow用户

发布于 2016-05-27 21:10:54

每当JavaScript执行function3函数时,都会创建一个'scope‘对象,以保存由您命名为变量的局部变量("foo")。注意,您的JavaScript代码不能直接访问这个作用域对象。因此,"foo“值对于内部函数是可用的,尽管外部函数已经返回。

JavaScript是否遍历某种闭包链,类似于它如何遍历原型链?

是。“范围对象形成一个称为范围链的链,类似于JavaScript的对象系统使用的原型链。

闭包是函数和创建函数的作用域对象的组合。闭包允许您保存状态--因此,通常可以使用它们来代替对象“

点击此处阅读更多信息:

票数 4
EN

Stack Overflow用户

发布于 2016-05-27 20:25:36

变量存在于声明变量的作用域中,该作用域是全局变量或函数。

这里的关键字是作用域

在MSDN网站中作为精辟地解释

函数定义中声明的变量是本地变量。每次执行该函数时,都会创建和销毁该函数,并且该函数之外的任何代码都无法访问它。JavaScript不支持块作用域(其中一组大括号{。。}定义一个新的作用域),但在块作用域变量的特殊情况下除外。

编辑

实际上,它比这要复杂一些,参见学步格言关于JS作用域的文章。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37491626

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档