IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 从内存的角度浅谈JS中的闭包以及闭包造成的内存泄漏 -> 正文阅读

[JavaScript知识库]从内存的角度浅谈JS中的闭包以及闭包造成的内存泄漏

关于JavaScript中闭包以及对闭包所造成的的内存泄漏的一些理解。

什么是闭包?

一个可以访问外层作用域的函数就是一个闭包

关于闭包的概念在论坛里每个人都有自己的观点,其实不难理解。我们可以这样想,在一对嵌套函数中,子函数是一定具备访问父函数内部变量的本领的,子函数无论是否真的引用了父函数中的变量,它都始终具备这样的本领,那么在这一对嵌套函数中就形成了闭包。所以,从广义的角度讲**任何一个函数都是闭包,它都具备访问外层作用域的本领。**从狭义的角度讲,一个子函数确确实实的访问了父函数中的变量,那么它一定是一个闭包!


那么为什么内层的函数就可以访问到外层作用域的变量了呢?

友情提示:下面内容涉及到作用域和上下文相关的相关知识,不太懂的小伙伴可以点链接去看一下相关内容。

下面从内存的角度来分析:

function foo() {
    var a = 1

    function bar() {
        console.log(a)
    }
    return bar
}
var Bar = foo()
Bar()

// 控制台打印: 1

代码执行到第9行,foo( )函数被调用。此时会创建foo的函数上下文,函数上下文入栈。函数的上下文中包括变量对象VO,表示为AO活动对象,AO对象中包含a变量和bar函数,代码执行… 执行完毕后返回bar函数,foo函数上下文出栈。如下图:

请添加图片描述

代码执行到第十行,调用bar函数,同样创建上下文,bar函数上下文压入上下文栈,上下文中不光包含活动对象AO同样还包含着作用域链,这个作用域链中包括父级上下文中的活动对象(foo的活动对象AO)。所以,在执行bar函数(Bar())时就可以访问到外层函数中的a变量。下面的图就不画了,hhhhh关于作用域链,AO,VO这些词汇很陌生的小伙伴最好去看下前面的内容。


闭包带来的内存泄漏

我们来思考一个问题:我们在上面分析到第9行的时候说foo函数执行完毕会它对应的上下文会弹出上下文栈,那么在堆内存中的AO对象该何去何从呢?整常情况下该活动对象随后也会被销毁,但是在这个例子中这个AO是永远不会被销毁的。这就是因为闭包所造成的内存泄漏

我们把目光锁定到上面例子中的第9行,此时foo函数执行完毕 如下图所示:请添加图片描述

这里要注意,堆内存中的bar函数对象有一个属性scope(表示父级作用域),它指向的是父级的活动对象。我们注意红色箭头,这个bar函数对象里面的scope属性又引用着foo函数上下文的AO活动对象(形成闭包),而全局变量Bar引用着bar函数对象。根据这两层引用关系,从某种角度来说这个全局变量Bar也是“指向”这个AO活动对象的,所以无论在下面的代码中是否通过Bar()去调用bar函数,这层引用关系是永远存在的,这就造成了内存泄漏,这个AO活动对象一直得不到回收。

如果我们想要让内存中的AO对象和bar函数对象都得到回收也很简单,只需一步:Bar=null 。意思是让全局变量Bar去指向0x0这块地址,内存中的bar函数对象就不会被全局变量Bar引用了,所以内存中的对象就会被回收掉。


假想一下:如果变换成如下代码内存中将会怎样执行呢?

function foo() {
    var a = 1

    function bar() {
        console.log(a)
    }
    bar()
}
foo()

这里只有微小的改变,也就是foo函数没有返回bar函数并用一个全局变量引用。还是熟悉的味道:代码执行到第9行,创建foo函数上下文,该上下文入栈,里面的活动对象仍然是包括变量a和一个函数bar。foo函数代码执行,此时创建bar函数上下文,通过作用域链找到a变量,打印 1。bar函数上下文出栈,销毁,foo函数上下文出栈,销毁,同时AO也都会被回收。

说一千道一万,这一微小的变化就是在foo函数体内部并没有返回bar函数并被全局变量引用,所以这里面有闭包,但是没有内存泄漏。

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-11 12:37:51  更:2021-11-11 12:38:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 6:47:22-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码