JavaScript高级 |深入闭包

news2025/1/14 3:29:06
本文已收录于专栏
⭐️ 《JavaScript》⭐️

学习指南:

    • 闭包
    • 基本概念
    • 内存管理
    • 垃圾回收
    • GC算法-标记清除
    • GC算法-标记整理
    • GC算法-分代收集
    • GC算法-增量收集
    • GC算法-闲时收集
    • 内存泄露
    • 完结散花
    • 参考文献

闭包

闭包是JavaScript中非常容易让人迷惑的知识点。
《在你不知道的JavaScript》一书中,笔者这样评价闭包的重要性:“理解闭包可以看做是某种意义上的重生,但是需要付出非常的多的努力和牺牲才能理解这个概念”。
本篇文章将会详细带你了解闭包,深入闭包!

基本概念

我们先看闭包在计算机科学中的定义:

  • 闭包(Closure),又称为词法闭包(Lexical Closure)或函数闭包(function closure)。
  • 是在支持头等函数的编程语言中,实习词法绑定的一种技术。
  • 闭包在实现上是一个结构体,它存储了一个函数和一个关联环境
  • 闭包跟函数最大的区别在于当捕捉闭包的时候,它的自由变量会在捕捉是被确定,这样即使脱离了捕捉时的上下文,它也能照常运行。

我猜读者读到这里对闭包的概念还是一头雾水,别担心上面的定义过于官方和晦涩。
别急让我们举一个例子看看。

var name = "shenqi";
var age = 18;
var height = 180;

function foo(){
	var message = "Hello World";
  console.log(message,name,age,height);
}

在上面的例子中,我声明了三个变量和一个函数。
在函数中我有定义了一个变量并很自然的将定义的四个变量打印了出来。
那么问题就来了。
如果读者有其他编程语言基础的话会发现,像C、C++、java这样的语言,在函数中要想使用函数之外定义的变量,必须在调用时将以实参的形式传入函数。
比如:

var name = "shenqi";
var age = 18;
var height = 180;

function foo(name,age,height){
	var message = "Hello World";
  console.log(message,name,age,height);
}

但JavaScript则不同,即使不将外部的变量通过实参的方式传入函数,也照样能使用函数体之外的变量。

而这就是闭包发挥的作用。

无论深度、子函数是否被调用只要内部有用到外部的变量,就会把它们保存到同一个闭包上,而这些变量实际上是通过作用域链获取且绑定的。
小结:

  • 一个函数和对其周围状态(词法环境)的引用捆绑在一起,或者是函数被引用捆绑在一起这样的组合就是闭包。
  • 在JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。
  • 闭包可以在一个内层函数中访问到其外层函数的作用域。

再通俗的说:

一个普通函数function,如果它可以访问外层作用域的自由变量,那么这个函数与其作用域就是一个闭包。

内存管理

编程语言,在代码的执行过程中都需要给他分配内存的,一般分为需要手动管理内存和自动管理内存的两种类型。

手动管理内存:C、C++,包括早起的OC都需要手动来管理内存的申请和释放(malloc和free函数)

自动管理内存:Java、JavaScript、python、Swift都有自动帮助我们管理内存的机制。
但无论以什么方式来管理内存,内存的管理都会有如下的生命周期:

  • 分配申请你需要的内存
  • 使用分配的内存(存放一些东西如对象等)
  • 不需要时,对其进行释放

JavaScript的内存管理

JS会在定义数据时,给数据分配内存。
根据数据类型不同,JS的内存分配方式也有所区别。

  • 对于原始数据类型:直接在栈空间进行分配。
  • 对于复杂数据类型:会在堆内存开辟一块空间,并且将这块空间的指针返回值变量引用。

image.png

垃圾回收

手动释放内存的方式对开发者的要求极高,一不小心就会产生内存泄露,并且影响我们编写逻辑的代码效率。
所以现代的编程语言都是有自己的垃圾回收机制。

  • 垃圾回收的英文是(Garbage Collection),简称GC
  • 对于那些不再使用的对象,我们都称之为垃圾,它需要被回收,以释放更多的内存空间。
  • 很多的语言运行环境,都会自带垃圾回收器。
    • 如Java的JVM,JavaScript的运行环境JS引擎都会有内存垃圾回收器。
  • 垃圾回收器,我们也简称GC,所以大部分情况下GC指的就是垃圾回收器。

GC算法-标记清除

标记清除的核心思想是可达性
这个算法是设置一个根对象(root object),垃圾回收器会定期从这个根开始,找到从根开始有引用的对象,对于哪些没有引用到的对象,就认为是不常用的对象,然后通过系统的机制将其清除。
作用:可以很好的解决循环引用的问题。

GC算法-标记整理

和标记清除相似。
不同的是,回收期间同时会将保存的存储对象搬运汇集到连续的内存空间,从而整合空闲空间,避免内存碎片化;

GC算法-分代收集

对象被分成两组:新生代和旧生代
新生代:许多对象出现,完成他们的工作之后就会闲置下来,闲置的这些很快就会在检查的时候被清除。
旧生代:旧生代是在新生代时期没有被清除的一部分,会移动到内存专门存放旧生代的一篇区域,这片区域一般存放长期存放的对象,被检查的频率也会减少。

V8为了提供内存的管理效率,对内存进行非常详细的划分。 image.png

GC算法-增量收集

  • 如果有许多对象,并且我们试图一次遍历并标记整个对象集,则可能需要一些时间,并在执行过程中带来明显的延迟。
  • 所以引擎试图将垃圾收集工作分为即部分来做,然后将这几部分会逐一进行处理,这样一个明显的延迟就会被转换为许多微小的延迟。

GC算法-闲时收集

垃圾收集器只会在CPU空闲时尝试运行,以减少可能对代码的影响。

内存泄露

闭包很容易导致内存泄漏。闭包会携带包含其它的函数作用域,因此会比其他函数占用更多的内存。
过度使用闭包会导致内存占用过多,所以要谨慎使用闭包。
内存泄露:对于一些我们之后永远都不会再使用的对象,但是因为他们满足可达性等GC算法,所以GC它不知道要进行内存释放,而这些对象所占有的内存依旧保留着。
解决方法:将需要释放的对象,手动赋值成null即可。
我们需要将arr8手动回收。

  1. 此时 addr8 仍然具有可达性,所以GC无法将其清除。

image.png

arr8 = null;
  1. 当我们手动将arr8赋值为null时,VO对象原本储存的arr8的内存地址也会被置换为null。

image.png

  1. 于此同时,由GO对象指向arr8AO对象的作用域链也会消失。

image.png

  1. 由于arr8不再具有可达性,所以GC就自动将arr8以及关联的AO对象清除内存。

image.png

浏览器的优化

首先我们来思考一个问题
AO对象在没有销毁时,里面的所有属性是否都不会被释放?

function makeAdder(count){
	var name = "shenqi";
  var age = 18;
  var height = 1.88;
  
	function bar(){
    console.log(name,height);
  }
  
  return bar;
}

在上面的代码中,我定义了三个变量,但在函数中只引用了其中的nameheight属性,并未使用age。
然后通过debugger我们发现:
声明后bar函数后JS引擎创建的对应的AO对象中,并没有age的身影。
这就是浏览器针对不使用的属性做的优化,将其释放,使得age被销毁。

完结散花

ok以上就是对 JavaScript高级 |深入闭包 的全部讲解啦,很感谢你能看到这儿。如果有遗漏、错误或者有更加通俗易懂的讲解,欢迎小伙伴私信我,我后期再补充完善。

参考文献

coderwhy老师JS高级视频教程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/94189.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

灯泡与影子(三分)

题目描述: 有一天&#xff0c;小明发现他的影子长度随着他在灯泡和墙壁之间走动时会发生变化&#xff0c;一个突发奇想在他的脑海里闪过&#xff0c;他现在想知道他来回走动&#xff0c;他的影子的最大长度是多少&#xff1f; 输入格式: 第一行包含一个整数T (T < 100),表…

C语言 常用标准库函数代码实现

一、内存 1. memcpy函数 memcpy 函数用于 把资源内存&#xff08;src所指向的内存区域&#xff09; 拷贝到目标内存&#xff08;dest所指向的内存区域&#xff09;&#xff1b;拷贝多少个&#xff1f;有一个size变量控制拷贝的字节数&#xff1b; 函数原型&#xff1a;void …

网络工程毕业设计 SSM汽车租赁系统(源码+论文)

文章目录1 项目简介2 实现效果2.1 界面展示3 设计方案3.1 概述3.2 系统流程3.3 系统结构设计4 项目获取1 项目简介 Hi&#xff0c;各位同学好呀&#xff0c;这里是M学姐&#xff01; 今天向大家分享一个今年(2022)最新完成的毕业设计项目作品&#xff0c;【基于SSM的汽车租赁…

mitmproxy 抓包神器-2.抓取Android 和 iOS 手机 https 请求

前言 抓取手机请求的前提条件是确保手机和电脑在同一网段上&#xff0c;也就是说使用同一WiFi。 启动服务 mitmweb 命令启动服务&#xff0c;默认监听8080端口 (venv) D:\demo\mitmproxy_xuexi>mitmweb [11:59:49.361] HTTP(S) proxy listening at *:8080. [11:59:49.36…

linux redhat8.0 权限管理

在linux里面&#xff0c;一切皆文件&#xff0c;不同的用户对文件有不同的管理权限&#xff0c;而只有root用户能为其他用户分配权限。 读&#xff08;r&#xff09;写&#xff08;w&#xff09;执行&#xff08;x&#xff09;数字表示421文件&#xff08;默认644&#xff09;…

SpringBoot-OneDay

优势 创建独立的spring程序自动配置spring简化的maven配置内嵌tomcat提供生产就绪型功能&#xff0c;如指标&#xff0c;健康检查和外部配置特性 为基于Spring 的开发提供更快的入门体验 开箱即用&#xff0c;没有代码生成&#xff0c;也无需XML 配置。同时也可以修改默认值来…

【从零开始学习深度学习】28.卷积神经网络之NiN模型介绍及其Pytorch实现【含完整代码】

目录1. NiN块介绍2. 构建NiN模型3.NIN模型每层输出形状4. 获取Fashion-MNIST数据和训练NiN模型5. 总结前几篇文章介绍的LeNet、AlexNet和VGG在设计上的共同之处是&#xff1a;先以由卷积层构成的模块充分抽取空间特征&#xff0c;再以由全连接层构成的模块来输出分类结果。其中…

RocketMQ基本概念及功能

文章目录背景架构模型NameServer 名字服务器Broker 代理服务器生产者主题队列消息消息标签消息位点消费者消费位点消费者分组订阅关系参考文章背景 RocketMQ是阿里巴巴在2012年开发的分布式消息中间件&#xff0c;专为万亿级超大规模的消息处理而设计&#xff0c;具有高吞吐量…

【VScode插件开发】<二>插件实践开发+发布

开发环境配置完&#xff0c;就得好好琢磨开发内容了&#xff0c;不能老停留在hello world上呀&#xff01; 一、开发文档结构分析 1.Package.json {"name": "kidtest","displayName": "KidTest","description": "for…

Gnoppix Linux系统发布

导读基于 Kali Linux 的 Linux 滚动发行版 Gnoppix 22.12 带来了 GNOME 43、Linux 内核 6.0 和新的升级。作为传统的现场 CD 发行版 Knoppix 项目的继承者&#xff0c;​​Gnoppix Linux​​ 是专门为渗透测试和反向工程而设计的。它为网页应用安全和数字权利保护进行了优化。除…

Java也可以轻松编写并发程序

如今&#xff0c;多核处理器在服务器&#xff0c;台式机及笔记本电脑上已经很普遍了&#xff0c;同时也被应用在更小的设备上&#xff0c;比如智能手机和平板电脑。这就开启了并发编程新的潜力&#xff0c;因为多个线程可以在多个内核上并发执行。在应用中要实现最大性能的一个…

SpringBoot+Vue实现前后端分离的小而学在线考试系统

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…

访问者模式(Visitor)

参考&#xff1a; 模板方法设计模式 (refactoringguru.cn) design-patterns-cpp/TemplateMethod.cpp at master JakubVojvoda/design-patterns-cpp GitHubhttps://github.com/JakubVojvoda/design-patterns-cpp/blob/master/state/State.cpp) 文章目录一、什么是访问者模式…

【Python机器学习】Sklearn库中Kmeans类、超参数K值确定、特征归一化的讲解(图文解释)

一、局部最优解 采用随机产生初始簇中心 的方法&#xff0c;可能会出现运行 结果不一致的情况。这是 因为不同的初始簇中心使 得算法可能收敛到不同的 局部极小值。 不能收敛到全局最小值&#xff0c;是最优化计算中常常遇到的问题。有一类称为凸优化的优化计算&#xff0c;不…

数字货币市场风暴肆虐,币圈人应该把握哪些新的赛道机遇

11月11日&#xff08;周五&#xff09;美股盘前&#xff0c;曾经为全球第二大加密货币交易所FTX在推特发布了申请破产保护的声明&#xff0c;创始人SBF已经辞去CEO职务。据声明&#xff0c;FTX已经任命John J. Ray III 担任CEO&#xff0c;SBF还将协助相关破产事宜。据FTX在推特…

[附源码]Python计算机毕业设计Django面向高校活动聚App

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

记录--三分钟打造自己专属的uni-app工具箱

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 介绍 可曾想过我们每次创建新项目&#xff0c;或者换地方写程序&#xff0c;都要把之前写过的工具类找出来又要复制粘贴一遍有些麻烦&#xff0c;尤其是写uni-app自定义模板主要还是开发工具完成的。这…

反序列化漏洞之CVE-2016-7124

目录 魔术函数 发生条件 靶场练习 魔术函数 __constuct: 构建对象的时被调用 __destruct: 明确销毁对象或脚本结束时被调用 __invoke: 当以函数方式调用对象时被调用 __toString: 当一个类被转换成字符串时被调用 __wakeup: 当使用unserialize时被调用&#xff0c;可用于做些…

【python】pandas 之 DataFrame、Series使用详解

目录 一&#xff1a;Pandas简介 二&#xff1a;Pandas数据结构 三&#xff1a;Series 四&#xff1a;字典生成Series 五&#xff1a;标量值生成Series 六&#xff1a;Series类似多维数组 七&#xff1a;Series类似字典 八&#xff1a;矢量操作与对齐 Series 标签 九…

对话交通银行:中国金融业数据仓库有哪些重要趋势?

数字经济时代&#xff0c;什么才是金融机构的核心竞争力&#xff1f;笔者访谈了交通银行软件开发中心总经理刘雷。刘雷指出&#xff1a;“数据和数据能力是金融机构发展的核心竞争力”。 当下&#xff0c;金融机构的数字化转型正迈入纵深阶段&#xff0c;使得两大核心诉求更加…