什么是闭包?从底层解释闭包的运行

本文通过解析两个Python闭包示例,深入浅出地讲解了闭包的运行原理,包括预编译过程、作用域链、执行上下文等概念,并探讨了闭包在实现变量共享、缓存、函数封装等方面的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前看过廖雪峰老师的闭包讲解,当时不明白其中的运行原理,今天在看了渡一的js课程后,明白了闭包的原理。那就举两个例子来解释下。

首先要了解预编译中的几个名词:

GO对象(Global Object),全局环境下创建的执行期上下文,就是全局作用域。
AO对象(Activation Object),也叫执行期上下文。在函数被执行前一刻创建,可以称为是局部环境、局部作用域。
Scope chain(作用域链),被创建的局部作用域会继承父级的作用域,形成一条作用域链。

再记住一点

但凡是内部的函数被保存到了外部它一定生成闭包。内部函数会保存外部函数的劳动成果,保存了还没执行,被放到了外部,而外部的函数自身AO就被内部的闭包函数保存了。

在一个函数的执行前有个预编译,当函数执行时,会创建一个称为执行期上下文的内部对象,一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,执行上下文被销毁

步骤如下

  1. 创建AO对象(Activation Object),执行期上下文。
  2. 寻找函数的形参和内部的变量声明,将变量声明和形参名作为AO属性名,如果有重复则跳过,初始值为undefined。
  3. 将实参的值放到形参里面去,将实参值和形参统一。函数内变量声明的值传递到AO对应的属性名。
  4. 在函数体内部寻找函数声明,创建AO属性名,属性值为函数体。
  5. GO除了没第三步,其它都和AO一样。

注意!
接下来看廖雪峰老师,讲python闭包那节课中的两个例子

def count():
    fs = [ ]
    for i in range(1, 4):  
        def f():                             
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()
--------------------------------
>>> f1()
9
>>> f2()
9
>>> f3()
9

按上面的理论来看,在for循环结束后,原本的fs = [ ]从一个空数组变成了fs = [ f , f , f ],里面都是一样的函数名。
并且在循环体结束后,i = 3。
此时 f1, f2, f3 = count(),所继承的东西是一样的,都是函数名 f
在这里,因为函数b被return抛出来了,它带着a的AO和GO,而在a的AO里i = 3。
所以在执行f1, f2, f3时,结果就都等于9了。

然后看第二个例子:

def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i))   # f(i)立刻被执行,因此i的当前值被传入f()
    return fs
    
f1, f2, f3 = count()    
---------------------------------
>>> f1()
1
>>> f2()
4
>>> f3()
9

在count的AO里,空数组从fs =[ ]变成了fs = [ f(1) , f(2) , f(3) ]

这里就不继续列出函数f,g的AO了。
直接从return fs开始。这时候f1, f2, f3从数组中被赋予了三个不同的函数,这三个函数是以数组的形式,被闭包返回了出来,这三个函数都得到了count的AO和GO

当执行f1, f2, f3时,其实执行的是被返回的g,函数g执行的就是j * j这个表达式。
而由于给数组末尾添加的是f (i),也就是 f(1) , f(2) , f(3) ,将实参替换形参,就得出了1,4,9的结果。

底层的运行大概就是这样了,但还有很多东西没有写出来,闭包最重要的就是弄明白AO和GO的运行步骤、作用域链继承,这些懂了,闭包就没问题了。

闭包的作用:
1.实现共有变量。
2.可以用作缓存。
3.可以实现函数封装,及属性私有化。
4.模块化开发,防止污染全局变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值