美文网首页
闭包的实现原理

闭包的实现原理

作者: AAA前端 | 来源:发表于2021-07-09 12:57 被阅读0次

    作用域和作用域链

    在 JavaScript 中, 作用域为可访问变量,对象,函数的集合。

    全局变量

    变量在函数外定义,即为全局变量。

    全局变量有 全局作用域: 网页中所有脚本和函数均可使用。

    在javascript中的全局作用域其实就是window(Global Object)

    优点:可重复使用,随处可用
    缺点:会造成全局污染

    局部作用域

    变量在函数内声明,变量为局部作用域。

    局部变量:只能在函数内部访问。

    临时创建的活动对象AO(Activation Object)、该对象包含了函数的所有局部变量、命名参数、参数集合以及this,当运行时上下文被销毁、活动也会被销毁

    优点:不污染全局
    缺点:不可重复使用、仅在函数内可以使用

    作用域链

    一般情况下,变量取值到 创建 这个变量 的函数的作用域中取值。

    但是如果在当前作用域中没有查到值,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链

    闭包

    有权访问另一个函数作用域中的变量的函数;一般情况就是在一个函数中包含另一个函数。
    特点:

    • 闭包是一个函数,而且存在于另一个函数当中
    • 闭包可以访问到父级函数的变量,且该变量不会销毁

    闭包的原理
    闭包的实现原理,其实是利用了作用域链的特性

    通过一段闭包的代码,我们又这段代码讲讲闭包的原理

        function addAge(){
            var age = 21;
            return function(){
                age++;
                console.log(age);
            }
        }
        var clourse = addAge();
        clourse();
        clourse();
        clourse();
    
    

    第一阶段:在内存中创建执行执行环境栈、把全局对象window压入栈底、在window中声明变量

    image.png

    第二阶段:
    1、在栈中添加addAge的函数调用
    2、为addAge函数创建活动对象AO、根据addAge函数的scope可以知道其活动对象指向window
    3、window对象中的clourse变量记录着addAge()返回的匿名函数的地址[现在addAge()和clourse变量都可以找到匿名函数和addAge()产生的AO]

    image.png

    第三阶段:addAge()调用完毕出栈、其对活动对象AO的引用也随之消失。
    由于匿名函数中的scope引用着活动对象AO、匿名函数的地址也被clourse变量记录着。因此,addAge()虽然出栈了,对它的活动对象的引用也消失了,但是其活动对象被匿名函数的scope拽着、所以无法释放不会被回收。
    大家观看蓝色的箭头,其实可以发现、蓝色的箭头已经形成了一个闭环了。
    此时,由图也可以看出,活动对象AO只能通过clourse变量来找到。这里形成了一个闭包。保存了addAge()函数中的局部变量,使其可以重复使用,但是又不会造成全局污染。这就是闭包的一个使用场景:保存现场。
    至于怎么调用重复使用局部变量,具体过程请看下面两幅图。

    image.png

    第四阶段:
    clourse()进栈,产生clouse()的活动对象AO,根据它的scope可以知道它的parent指向addAge()产生的活动对象AO。
    clouse()执行age++,由于在它自己的作用域里面没有age、于是它会到上一级作用域查找age,它在它的上一级作用域中找到了age,于是对其进行了age++,age从21变成了22。执行console.log(age)输出22。

    image.png

    第五阶段:
    clourse()出栈,因为clourse产生的AO没有scope拽着它,因此clourse的AO是可以正常释放的。函数出栈,其AO被JS的垃圾回收机制回收。
    clourse变量中的匿名函数中的scope依旧拽着addAge()产生的活动对象AO,于是这个活动对象依旧无法被释放[而且这个AO现在只能被clourse找到、clourse可以重复使用这个AO里面的局部变量age、又不会造成全局污染]

    image.png

    闭包就像一层保护膜,只要引用的函数一直存在,闭包就保护该作用域内的变量不被垃圾回收。针对在函数声明那一时间点的作用域内的所有函数和变量,闭包创建了一个“安全气泡”,因此函数获得了执行操作所需要的所有东西,包含了函数及其变量,和函数本身在一起。

    参考:https://segmentfault.com/a/1190000011504517

    相关文章

      网友评论

          本文标题:闭包的实现原理

          本文链接:https://www.haomeiwen.com/subject/olrfpltx.html