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

闭包的实现原理

作者: 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

相关文章

  • 闭包的实现原理

    作用域和作用域链 在 JavaScript 中, 作用域为可访问变量,对象,函数的集合。 全局变量 变量在函数外定...

  • 从 QuickJS 源码理解 JavaScript 的闭包

    摘要 本文从 QuickJS 源码的角度分析 JavaScript 语言中的闭包的实现原理,首先介绍闭包的概念,然...

  • 选项卡

    实现方式:1、闭包2、动态获取-设置属性 实现效果: 先设置统一样式: html: css: 一、闭包 1.原理 ...

  • 自定义结构体方法示例

    自定义结构体 带有闭包的函数变量,其底层实现原理和带有闭包的匿名函数类似,接手值被隐含的绑定到方法值的闭包环境中,...

  • JS 闭包的实现原理

    函数都有自己的执行环境,该环境定义了变量或者函数访问数据的权限,当离开执行环境后,该环境内的变量会被销毁。 上例a...

  • 闭包的声明 实现以及调用

    1闭包的声明 闭包的实现 闭包的调用

  • Python闭包

    闭包 = 环境变量 + 函数 调用闭包内部的环境变量 闭包的经典误区 闭包与非闭包实现人类走路 非闭包 闭包

  • Swift-08:闭包

    1.分析闭包以及闭包捕获变量的原理2.逃逸闭包 & 非逃逸闭包 一、闭包 闭包是一个捕获了全局上下文的常量或者变量...

  • JavaScript - 闭包

    理解 关于闭包 答案: 用arguments.callee和闭包实现的函数封装 应用 利用闭包实现自动递增计数

  • Swift-进阶 :闭包(一)使用&捕获原理

    本文主要分析闭包以及闭包捕获变量的原理 闭包 闭包是一个捕获了全局上下文的常量或者变量的函数,通俗来讲,闭包可以是...

网友评论

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

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