1: function createCounter() {
2: let counter = 0
3: const myFunction = function() {
4: counter = counter + 1
5: return counter
6: }
7: return myFunction
8: }
9: const increment = createCounter()
10: const c1 = increment()
11: const c2 = increment()
12: const c3 = increment()
13: console.log('example increment', c1, c2, c3)
- 同上,第
1-8
行。我们在全局执行上下文中创建了一个新的变量createCounter
,它得到了指定的函数定义。 - 同上,第
9
行。我们在全局执行上下文中声明了一个名为increment
的新变量。 - 同上,第
9
行。我们需要调用createCounter
函数并将其返回值赋给increment
变量。 - 同上,第
1-8
行。调用函数,创建新的本地执行上下文。 - 同上,第
2
行。在本地执行上下文中,声明一个名为counter
的新变量并赋值为0
。
- 第
3-6
行。声明一个名为myFunction
的新变量,变量在本地执行上下文中声明,变量的内容是另一个函数定义。如第4
行和第5
行所定义,现在我们还创建了一个闭包,并将其作为函数定义的一部分。闭包包含作用域中的变量,在本例中是变量counter
(值为0
)。 - 第
7
行。返回myFunction
变量的内容,删除本地执行上下文。myFunction
和counter
不再存在。控制权交给了调用上下文,我们返回函数定义和它的闭包,闭包中包含了创建它时在作用域内的变量。 - 第
9
行。在调用上下文(全局执行上下文)中,createCounter
返回的值被指定为increment
,变量increment
现在包含一个函数定义(和闭包),由createCounter返回的函数定义,它不再标记为myFunction
,但它的定义是相同的,在全局上下文中,称为increment
。 - 第
10
行。声明一个新变量c1
。 - 继续第
10
行。查找变量increment
,它是一个函数,调用它。它包含前面返回的函数定义,如第4-5
行所定义的。(它还有一个带有变量的闭包)。 - 创建一个新的执行上下文,没有参数,开始执行函数。
- 第
4
行。counter = counter + 1
,寻找变量counter
,在查找本地或全局执行上下文之前,让我们检查一下闭包,瞧,闭包包含一个名为counter
的变量,其值为0
。在第4
行表达式之后,它的值被设置为1
。它再次被储存在闭包里,闭包现在包含值为1
的变量counter
。 - 第
5
行。我们返回counter的值
,销毁本地执行上下文。 - 回到第
10
行。返回值1
被赋给变量c1
。 - 第
11
行。我们重复步骤10-14
。这一次,在闭包中此时变量counter
的值是1。它在第12
行设置的,它的值被递增并以2
的形式存储在递增函数的闭包中,c2
被赋值为2
。 - 第
12
行。重复步骤10-14
行,c3
被赋值为3。 - 第13行。我们打印变量
c1 c2
和c3
的值。
你可能会问,是否有任何函数具有闭包,甚至是在全局范围内创建的函数?答案是肯定的。在全局作用域中创建的函数创建闭包,但是由于这些函数是在全局作用域中创建的,所以它们可以访问全局作用域中的所有变量,闭包的概念并不重要。
当函数返回函数时,闭包的概念就变得更加重要了。返回的函数可以访问不属于全局作用域的变量,但它们仅存在于其闭包中。
闭包就相当于一个背包,当一个函数被创建并传递或从另一个函数返回时,它会携带一个背包,里面存储的是函数声明时作用域内的所有变量,这个背包就是闭包!
最后一次更新于2021-09-26
0 条评论