返回顶部
首页 > 资讯 > 精选 >javascript中浏览器是如何看闭包的
  • 844
分享到

javascript中浏览器是如何看闭包的

2023-06-25 14:06:35 844人浏览 独家记忆
摘要

小编给大家分享一下javascript中浏览器是如何看闭包的,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!前言闭包,是javascript的一大理解难点,网上关于

小编给大家分享一下javascript中浏览器是如何看闭包的,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

前言

闭包,是javascript的一大理解难点,网上关于闭包的文章也很多,但是很少有能让人看了就彻底明白的文章。究其原因,我想是因为闭包涉及了一连串的知识点。只有把这一连串的知识点都理解透彻,实现一个概念的闭环,才可以真正理解它。今天打算换个角度来理解闭包,从内存分配与回收的角度阐述,希望能帮助你真正消化掉所看到的闭包知识,同时也希望本文是你看的最后一篇关于闭包的文章。

大家看本文中的配图时,请牢记箭头的指向。因为它是根对象window遍历内存垃圾所依赖的原则,能够从window开始,顺着箭头找到的都不是内存垃圾,不会被回收掉。只有那些找不到的对象才是内存垃圾,才会在适当的时机被GC回收。

闭包简介

函数嵌套函数时,内层函数引用了外层函数作用域下的变量,并且内层函数被全局环境下的变量引用,就形成了闭包。

闭包实质上是函数作用域的副产物。

关于闭包我们需要特别重视的一点是函数内部定义的所有函数共享同一个闭包对象。什么意思呢?看如下代码:

var afunction b() {  var c = new String('1')  var d = new String('2')  function e() {    console.log(c)  }  function f() {    console.log(d)  }  return f}a = b()

上面代码中f引用了变量d,同时f被外部变量a引用,所以形成闭包,导致变量d滞留在内存中。我们思考一下,那么变量c呢?好像我们并没有用到c,应该不会滞留在内存中吧。然后事实是c也会滞留在内存中。如上代码形成的闭包包含两个成员,c和d。这种现象成为函数内闭包共享。

为什么说需要特别重视这个特性呢?因为这个特性,如果我们不仔细的话,很容易写出导致内存泄漏的代码。
关于闭包的概念性的东西,我就讲这么多了,但是如果真正理解好闭包,还是需要搞明白几个知识点

  • 函数作用域链

  • 执行上下文

  • 变量对象、活动对象

这些内容大家可以谷歌百度之,大概理解一下。接下来我会讲如何从浏览器的视角来理解闭包,所以不做过多讲解。

如何判别内存垃圾

现代浏览器的垃圾回收过程比较复杂,详细过程大家可以自行Google之。这里我只讲如何判定内存垃圾。大体上可以这么理解,从根对象开始寻找,只要能顺着引用找到的,都不能被回收。顺着引用找不到的对象被视为垃圾,在下一个垃圾回收节点被回收。寻找垃圾,可以理解为顺藤摸瓜的过程。

闭包的内存表示

从最简单的代码入手,我们看下全局变量定义。

var a = new String('小歌')

这样一段代码,在内存里表示如下

javascript中浏览器是如何看闭包的

在全局环境下,定义了一个变量a,并给a赋值了一个字符串,箭头表示引用。

我们再定义一个函数:

var a = new String('小歌')function teach() {  var b = new String('小谷')}

内存结构如下:

javascript中浏览器是如何看闭包的

一切都很好理解,如果你细心的话,你会发现函数对象teach里有一个叫[[scopes]]的属性,这是什么东东?函数创建完为什么会有这个属性。很高兴你能问到这一点,也是理解闭包很关键的一点。

请谨记: 函数一旦创建,javascript引擎会在函数对象上附加一个名叫作用域链的属性,这个属性指向一个数组对象,数组对象包含着函数的作用域以及父作用域,一直到全局作用域

所以上图可以简单理解为:teach函数是在全局环境下创建的,所以teach的作用域链只有一层,那就是全局作用域global

需要明确的是,浏览器下global指向window对象,nodejs环境global指向global对象

请再次谨记: 函数在执行的时候,会申请空间创建执行上下文,执行上下文会包含函数定义时的作用域链,其次包含函数内部定义的变量、参数等,当函数在当前作用域执行时,会首先查找当前作用域下的变量,如果找不到,就会向函数定义时的作用域链中查找,直到全局作用域,如果变量在全局作用域下也找不到,则会抛出错误。

我们都知道,函数执行的时候,会创建一个执行上下文,其实就是在申请一块栈结构的内存空间,函数中的局部变量都在这块空间中分配,函数执行完毕,局部变量在下一个垃圾回收节点被回收。OK,我们再次升级一下代码,看一下函数运行时内存的结构。

var a = new String('小歌')function teach() {  var b = new String('小谷')}teach()

内存表示如下:

javascript中浏览器是如何看闭包的

很明显,我们可以看到,函数在执行过程中仅仅做了一个局部变量的赋值,并未与全局环境下的变量发生关系,所以我们从window对象沿着引用(图中的箭头)寻找的话,是找不到执行上下文中的变量b的。因此函数执行完后,变量b将被回收。

我们再次升级一下代码:

var a = new String('小歌')function teach() {  var b = new String('小谷')  var say = function() {    console.log(b)  }  a =  say}teach()

内存表示如下:

javascript中浏览器是如何看闭包的

注:灰色表示的是无法从根对象跟踪到的对象。

函数执行顺序:

  1. 函数teach开始执行前,申请栈空间,上图蓝色方块。

  2. 创建上下文scope(类栈结构),并将teach函数定义时的[[scopes]]压入到scope中。

  3. 初始化变量b(变量提升),创建函数say,初始化say的scopes属性,首先将函数teach的scopes压入函数say的[[scopes]] 中。由于say引用了变量b,形成闭包closure。所以我们还要将closure对象压入函数say的[[scopes]]。

  4. 创建变量对象local,指向局部变量b和say,并将local压入步骤2的scope中。

  5. 函数开始执行

    1. 给变量b赋值字符串对象'小谷'。

    2. 将全局变量a指向函数say。

函数执行完毕,正常情况下变量b应该被释放了。但是我们发现,沿着window找下去,是能够找到b的,根据我们前面讲的判定内存垃圾的原理得知,b不是内存垃圾,所以b不能被释放,这就是为什么闭包会让函数内变量保存在内存中的原因。

再次升级代码,我们看下闭包共享的内存表示:

var a = new String('0')function b() {  var c = new String('1')  var d = new String('2')  function e() {    console.log(c)  }  function f() {    console.log(d)  }  return f}a = b()

javascript中浏览器是如何看闭包的

灰色表示的图形是内存垃圾,将会被垃圾回收器回收。

上图很容易得出,虽然函数f没有用到变量c,但是c被函数e引用,所以变量c存在于闭包closure中,从window对象开始寻找能够找到变量c,所以变量c也不能释放。

你也许会问了,这种特性是如何能导致内存泄漏的呢?好吧,思考如下一段代码,比较经典的meteor内存泄漏问题。

var t = null;        var replaceThing = function() {            var o = t            var unused = function() {                if (o)                    console.log("hi")            }            t = {                    longStr: new Array(1000000).join('*'),                    someMethod: function() {                      console.log(1)                    }                }        }        setInterval(replaceThing, 1000)

这段代码是有内存泄漏的,在浏览器中执行这段代码,你会发现内存不断上升,虽然gc释放了一些内存,但是仍然有一些内存无法释放,而且是梯度上升的。如下图

javascript中浏览器是如何看闭包的

这种曲线说明是有内存泄漏的,我们可以通过开发工具去分析哪些对象没有被回收掉。事实上我可以告诉大家,没有释放掉的内存其实就是我们每次创建的大对象t。我们通过画图的方式来看下:

javascript中浏览器是如何看闭包的

上面这张图是假设replaceThing函数执行了三次,你会发现,每次我们给变量t赋予一个大对象的时候,由于闭包共享的缘故,之前的大对象仍然能够从window对象跟踪到,所以这些大对象都不能被回收掉。其实真正对我们有用的是最后一次为t赋予的大对象,那么之前的对象则造成了内存泄漏。

可以想象,假如我们没有意识到这一点,任由程序一直运行下去,浏览器很快就会崩溃。

解决这个问题的方式也很简单,每次执行完代码,将变量o置为null即可。

以上是“javascript中浏览器是如何看闭包的”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网精选频道!

--结束END--

本文标题: javascript中浏览器是如何看闭包的

本文链接: https://lsjlt.com/news/305326.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • javascript中浏览器是如何看闭包的
    小编给大家分享一下javascript中浏览器是如何看闭包的,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!前言闭包,是javascript的一大理解难点,网上关于...
    99+
    2023-06-25
  • 详细聊聊浏览器是如何看闭包的
    目录前言闭包简介如何判别内存垃圾闭包的内存表示结语前言 闭包,是javascript的一大理解难点,网上关于闭包的文章也很多,但是很少有能让人看了就彻底明白的文章。究其原因,我想是因...
    99+
    2024-04-02
  • 浏览器中如何关闭javascript
    小编给大家分享一下浏览器中如何关闭javascript,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!关闭方法:1、打开浏览器,点击右上角的“菜单”按钮,在打开的下...
    99+
    2023-06-14
  • javascript如何关闭浏览器
    这篇文章主要介绍了javascript如何关闭浏览器,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。JavaScript是什么JavaScript是一种直译式的脚本语言,其解释...
    99+
    2023-06-14
  • Safari浏览器里如何关闭javascript
    这篇文章主要介绍了Safari浏览器里如何关闭javascript,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。 ...
    99+
    2024-04-02
  • 手机浏览器中javascript 关闭浏览器弹出提示框
    近年来,随着手机智能化程度的不断提高,越来越多的人开始使用手机浏览器来进行网页浏览和操作。作为一名开发人员,如何在手机浏览器中实现一些常见的功能也变得尤为重要。本文将介绍如何利用javascript技术,在手机浏览器中关闭浏览器弹出的提示框...
    99+
    2023-05-14
  • 如何用JavaScript检测当前浏览器是无头浏览器
    目录什么是无头浏览器(headless browser)?为什么叫“无头”浏览器?为什么要检测无头浏览器?检测无头浏览器User agent插件 Plugins语言WebGL浏览器特...
    99+
    2024-04-02
  • 如何使用JavaScript检测当前浏览器是无头浏览器
    这篇文章将为大家详细讲解有关如何使用JavaScript检测当前浏览器是无头浏览器,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。javascript是一种什么语言javascript是一种动态类型、弱类型...
    99+
    2023-06-14
  • javascript关闭浏览器事件的方法
    小编给大家分享一下javascript关闭浏览器事件的方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!javascript关闭浏览器事件的方法:1、使用onbe...
    99+
    2023-06-14
  • windows中ie浏览器如何看是哪个版本
    这篇文章主要讲解了“windows中ie浏览器如何看是哪个版本”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“windows中ie浏览器如何看是哪个版本”吧!...
    99+
    2022-12-16
    windows ie
  • 浏览器如何解析javascript
    随着互联网技术的不断发展,JavaScript语言已经成为了前端开发的必备技能。JavaScript是一种脚本语言,它可以在浏览器中执行,以实现网页的交互效果,如表单验证、动态加载内容、异步请求等等。那么浏览器是如何解析JavaScript...
    99+
    2023-05-14
  • Windows7如何关闭IE浏览器选项卡浏览以防误关闭
      我们在使用IE浏览器时,默认都是使用选项卡浏   设置   1、打开IE浏览器,然后点击菜单栏上的【工具】,   2、打开Internet选项后点击选项卡区域的“设置”按钮;   3、在选...
    99+
    2023-06-12
    Win7 IE浏览器 选项卡 IE 浏览器
  • 怎么在ie浏览器中关闭javascript脚本
    怎么在ie浏览器中关闭javascript脚本?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。在桌面桌面是开始菜单中找到IE浏览器,然后打开它。打开之后,来到它默认打开的页面,然...
    99+
    2023-06-14
  • 浏览器中如何实现JavaScript计时器
    这篇文章将为大家详细讲解有关浏览器中如何实现JavaScript计时器,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。在 Web Worker中使用无限同步循环由于 Web...
    99+
    2024-04-02
  • IE浏览器如何启用javascript
    这篇文章主要介绍了IE浏览器如何启用javascript,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。 IE浏览...
    99+
    2024-04-02
  • 360浏览器如何禁止javascript
    这篇文章给大家分享的是有关360浏览器如何禁止javascript的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。禁止javascript的方法:1、打开浏览器,点击“菜单”按钮,在打开的列表中点击“设置”按钮;2...
    99+
    2023-06-14
  • 浏览器关闭javascript后的有什么影响
    这篇文章主要介绍“浏览器关闭javascript后的有什么影响”,在日常操作中,相信很多人在浏览器关闭javascript后的有什么影响问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”浏览器关闭javascri...
    99+
    2023-06-20
  • Win7如何如何设置QQ打开的浏览器是IE浏览器
      Win7下IE浏览器是自带的,如今也有很多的浏览器已经进入大家的电脑中,但是据我所知大多数用户还是习惯了使用IE浏览器。QQ广告已经进入我们的市场,很多用户都会经过QQ中的链接来打开一些网页但是往往经常打开的却不是大...
    99+
    2023-06-15
    Win7 浏览器 QQ链接 IE
  • 详解JavaScript中的闭包是如何产生的
    目录闭包的产生多个内部函数共享一个闭包对象结尾这次从内存管理的角度来看看,闭包是怎么产生的。 我们知道,在调用函数时,其实会产生临时的 调用栈。这些调用栈保存的是 执行上下本,并实际...
    99+
    2022-12-28
    JavaScript闭包如何产生 JavaScript闭包
  • 如何打开浏览器的JavaScript支持
    随着互联网技术的不断发展,网站变得越来越复杂,JavaScript也成为现代网站开发的一个重要组成部分。但是,在浏览网站时,有些人可能会遇到浏览器不支持JavaScript的情况。那么,如何打开浏览器的JavaScript支持呢?检查浏览器...
    99+
    2023-05-14
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作