资讯专栏INFORMATION COLUMN

理解闭包

fox_soyoung / 1244人阅读

摘要:我的理解就是还处于被引用状态。内存机制的内存空间分为栈堆其中栈存放变量,堆存放复杂对象。对堆内数据进行复制修改时理解闭包有了前面的铺垫,我们再来看看闭包是怎么回事。这种反常的现象我们就叫它,中文名闭包。这就是闭包形成的原因了。

知识小储备
ECMAScript 的数据有两种类型:基本类型值和引用类型值,基本类型指的是简单的数据段,引用类型指的是可能由多个值构成的对象。

Undefined、Null、Boolean、Number 和 String 是值类型,其他都是引用类型。

垃圾回收

我们创建的原始类型、对象、函数等等,都会占用内存。为了防止溢出,我们就需要对不用的数据进行删除。这就是垃圾回收。

可触及(Reachability)

JavaScript 内存管理的关键概念是可触及(Reachability)。
我的理解就是还处于被引用状态。
将全局(无论是window还是global)比作树根,我们创建的原始类型、对象、函数等等比作一个个枝杈。如果可以从window不断层的知道某个变量,那这个变量就是可触及的,不可回收的。

举个例子:

// user has a reference to the object
let user = {
  name: "John"
};

箭头代表的是对象引用。全局变量 "user" 引用了对象{name: "John"}(简称此对象为 John)。John 的 "name" 属性储存的是一个原始值,所以无其他引用。

如果覆盖 user,对 John 的引用就丢失了:

user = null;

现在 John 变得不可触及,垃圾回收机制会将其删除并释放内存。

内存机制

js的内存空间分为栈 (stack)、堆 (heap);其中栈存放变量,堆存放复杂对象。
借用一张图直观感受一下

栈内存

只能存放基本数据类型的数据和对象类型的引用地址也叫哈希码。里面的数据后进先出。
对栈内数据进行复制修改时:

堆内存

是用来存储 “数组类型” 和“对象类”的数据。特点是存储空间大。
对堆内数据进行复制修改时:

理解闭包

有了前面的铺垫,我们再来看看闭包是怎么回事。还是举个例子:

//决策层开会决定生产新一代phone手机,就弄了个叫PhoneFactory的企划案
let Proposal = function(){
    //新一代手机信息被封装在企划案中
    let  version = "XX", money = 10000
    return function (){
        //生产新的手机
        return {
            version: version,
            money: money
        }
    }
}
//执行者根据策划案建成了一个工厂, 工厂方法每执行一次就产出一个手机
let Factory = new Proposal();
let phone1 = Factory();
console.log(phone1.version)

对于手机的version, money而言, 它是策划书Proposal的内部变量,而Proposal的同级phone1应该是访问不到。但实际上我们还是拿到了手机的版本和价格数据。这种反常的现象我们就叫它Closure,中文名闭包。

原因

我们不管它为什么叫这个名字,先看看具体是什么原因产生的。
根据上面说的垃圾回收机制。函数Proposal在执行过之后(第16行)就没有引用。那么Proposal久应该被回收。里面的所有内部变量也应该被回收了。
但实际上 Proposal返回了一个新的函数Factory。而这个Factory是要能够访问到它生成时的同级以及父祖辈变量。而Proposal内部变量version, money就有了新的引用。因而阻止了被回收。就像Factory生成了一个新的泡泡把它能访问到的作用域包裹了起来。这就是闭包形成的原因了。

基于上面的js内存机制的知识,我们可以画出下面这张图:

图简陋了点。。。。
但也可以看出,对于变量version,money而言。虽然他们本身在proposal的黄色作用域中。但也在fatory生成的时候也被包含在了fatory打的可访问的作用域气泡内。不仅他们,甚至更外层的也都被包含在内。
在proposal这个泡泡破碎之后,只有当打的红色泡泡也破了,这些变量才会真的被回收。这也是为什么闭包用多了会影响性能的原因。

引用:

前端基础进阶:详细图解 JavaScript 内存空间
垃圾回收

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96310.html

相关文章

  • 多层级理解闭包

    摘要:第二梯队理解有了第一梯队的认识,我们慢慢修正大脑中对闭包的认识。理解这句话就可以很好的与闭包这两个字关联起来理解闭包这个概念了。总结第二梯队理解闭包是一个有特定功能的函数。第四梯队理解闭包通过访问外部变量,一个闭包可以维持这些变量。 闭包 闭包的概念困惑了我很久,记得当时我面试的时候最后一面有一个问题就是问题关于闭包的问题,然而到现在已经完全不记得当时的题目是啥了,但仍然能够回忆起当时...

    nemo 评论0 收藏0
  • 理解 JavaScript 闭包

    摘要:如何在初学就理解闭包你需要接着读下去。这样定义闭包是函数和声明该函数的词法环境的组合。小结闭包在中随处可见。闭包是中的精华部分,理解它需要具备一定的作用域执行栈的知识。 这是本系列的第 4 篇文章。 作为 JS 初学者,第一次接触闭包的概念是因为写出了类似下面的代码: for (var i = 0; i < helpText.length; i++) { var item = he...

    宠来也 评论0 收藏0
  • 谈谈我所理解闭包,js、php、golang里的closure

    摘要:当初看这个解释有点懵逼,理解成闭包就是函数中的函数了。里的闭包最近不满足于只干前端的活,开始用起了。里的闭包最近在学习语言,让我们来看一下语言里的闭包。在中,闭包特指将函数作为值返回的情况,被返回的函数引用了生成它的母函数中的变量。 本人开始接触编程是从js开始的,当时网上很多人说闭包是难点,各种地方对闭包的解释也是千奇百怪。如今开始接触js以外的各种编程语言,发现不光是js,php、...

    betacat 评论0 收藏0
  • 谈谈我所理解闭包,js、php、golang里的closure

    摘要:当初看这个解释有点懵逼,理解成闭包就是函数中的函数了。里的闭包最近不满足于只干前端的活,开始用起了。里的闭包最近在学习语言,让我们来看一下语言里的闭包。在中,闭包特指将函数作为值返回的情况,被返回的函数引用了生成它的母函数中的变量。 本人开始接触编程是从js开始的,当时网上很多人说闭包是难点,各种地方对闭包的解释也是千奇百怪。如今开始接触js以外的各种编程语言,发现不光是js,php、...

    zhoutao 评论0 收藏0
  • 简单理解JavaScript中的闭包

    摘要:闭包在我理解是一种比较抽象的东西。所以我写了一篇博文来方便自己理解闭包。那么现在我们可以解释一下闭包的第一个定义在计算机科学中,闭包是引用了自由变量的函数。循环中创建闭包在我们使用的关键字之前,闭包的一个常见问题就出现在循环中创建闭包。 零. 前言 从我开始接触前端时就听说过闭包,但是一直不理解闭包究竟是什么。上网看了各种博客,大家对闭包的说法不一。闭包在我理解是一种比较抽象的东西。所...

    sihai 评论0 收藏0
  • 理解Javascript的闭包

    摘要:但是闭包也不是什么复杂到不可理解的东西,简而言之,闭包就是闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。可惜的是,并没有提供相关的成员和方法来访问闭包中的局部变量。 (收藏自 技术狂) 前言:还是一篇入门文章。Javascript中有几个非常重要的语言特性——对象、原型继承、闭包。其中闭包 对于那些使用传统静态语言C/C++的程序员来说是一个新的语言特性。本文将...

    dayday_up 评论0 收藏0

发表评论

0条评论

fox_soyoung

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<