我编写这段代码是为了教会自己有关JavaScript闭包的知识:
function1 = function(){
var variable = "foo"
var function2 = function(argument){
console.log(variable + argument);
}
return function2
}
function3 = function1();
function3("bar");这印出了预期的"foobar“。但是变量在哪里呢?
它是function3的一个属性,还是存储在function3中的其他地方?JavaScript是否遍历某种闭包链,类似于它如何遍历原型链?它是不是储存在其他地方的记忆里?
我正试图更深入地理解这一点。
发布于 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和一个引用“父词法环境”的外部词汇环境(顾名思义)。
因此,在计算代码示例时,内存的初始状态(在执行任何操作之前)可能如下(简化):
+-(Global) lexical environment-+ +-Environment Record-+
+-------------+----------------+ +---------+----------+
| Environment | *--------+---> |function1|undefined |
| Record | | +---------+----------+
+-------------+----------------+ |function3|undefined |
| Outer | | +---------+----------+
| lexical | (empty) |
| environment | |
+-------------+----------------+全球环境没有任何外部环境,因为它在顶部。function1和function3是两个尚未初始化的绑定(赋值尚未评估)。
在创建函数(评估function1 = function() { ... })之后,内存如下所示:
+------------------------------------------------------------------------+
| |
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。正如我在一开始所说的,每当函数被执行时,都会创建一个新的词法环境。让我们看一下在输入函数之后的内存:
+------------------------------------------------------------------------+
| |
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之后,内存具有以下结构:
+------------------------------------------------------------------------+
| |
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 | | | +---------------+---------+
| +-------------+--------+-------+
| |
+-------------------------+类似于function1,function2有一个通过调用function2创建的环境的引用。此外,function3引用我们创建的函数,因为我们从function1返回它。
最后一步:调用function3('bar')
+------------------------------------------------------------------------+
| |
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时,会发生以下情况:由于它不存在于环境本身的记录中,它会查看它的“外部词法环境”的记录,因为它有一个引用。
发布于 2016-05-27 21:10:54
每当JavaScript执行function3函数时,都会创建一个'scope‘对象,以保存由您命名为变量的局部变量("foo")。注意,您的JavaScript代码不能直接访问这个作用域对象。因此,"foo“值对于内部函数是可用的,尽管外部函数已经返回。
JavaScript是否遍历某种闭包链,类似于它如何遍历原型链?
是。“范围对象形成一个称为范围链的链,类似于JavaScript的对象系统使用的原型链。
闭包是函数和创建函数的作用域对象的组合。闭包允许您保存状态--因此,通常可以使用它们来代替对象“
点击此处阅读更多信息:
https://stackoverflow.com/questions/37491626
复制相似问题