当前位置: 首页 > article >正文

【JavaScript】二十九、垃圾回收 + 闭包 + 变量提升

文章目录

  • 1、作用域
    • 1.1 局部作用域
    • 1.2 全局作用域
    • 1.3 作用域链
  • 2、JC垃圾回收机制♻️
  • 3、GC算法
    • 3.1 引用计数法
    • 3.2 标记清除法
  • 4、闭包
    • 4.1 定义
    • 4.2 闭包的应用:实现数据的私有
  • 5、变量提升

1、作用域

即一个范围,离开了这个范围,这个变量就不能再被访问到

1.1 局部作用域

又分为:

  • 函数作用域
  • 块作用域

函数作用域:

  • 函数内部声明的变量,在函数外部无法被访问
  • 函数的形参也是函数内部的局部变量

在这里插入图片描述

块作用域:

JS中,使用 { } 包裹的代码称为代码块,代码块内部声明的变量外部将有可能无法被访问

在这里插入图片描述

  • let 声明的变量会产生块作用域,var 不会产生块作用域
  • const 声明的常量也会产生块作用域
  • 不同代码块之间的变量无法互相访问
  • 推荐使用 let 或 const

1.2 全局作用域

即script 标签 和 .js 文件 的 最外层声明的变量

在这里插入图片描述

  • 为 window 对象动态添加的属性默认也是全局的,不推荐!
  • 函数中未使用任何关键字声明的变量为全局变量,不推荐!
<body><script>function m1() {num = 10}// 调用一下m1()// 成功拿到了10console.log(num)</script>
</body>
<body><script>window.myVar = '自定义'// 自定义console.log(window.myVar)</script>
</body>

1.3 作用域链

输出结果:2
在这里插入图片描述

作用域链本质上是底层的变量查找机制

  • 在函数被执行时,会优先查找当前函数作用域中查找变量(就近)
  • 如果当前作用域查找不到则会依次逐级查找父级作用域直到全局作用域,上面例子中,就存在g函数作用域 --> f函数作用域 --> 全局作用域这个链路

2、JC垃圾回收机制♻️

整个过程:

  • 内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存
  • 内存使用:即读写内存,也就是使用变量、函数等
  • 内存回收:使用完毕,由垃圾回收自动回收不再使用的内存,即GC
<body><script>// 为变量分配内存const i = 1const str = 'test'// 为对象分配内存const obj = {uname: 'tom',age: 18}// 为函数分配内存function sum(a, b) {return a + b} </script>
</body>
  • 全局变量一般不会回收(关闭页面回收)
  • 一般情况下局部变量的值, 不用了, 会被自动回收掉
  • 如果不再用到的内存,没有及时释放,就叫做内存泄漏

3、GC算法

3.1 引用计数法

IE采用的引用计数算法, 定义“内存不再使用”,就是看一个对象是否有指向它的引用,没有引用了就回收对象 算法:

  • 跟踪记录被引用的次数
  • 如果被引用了一次,那么就记录次数1,多次引用会累加 ++
  • 如果减少一个引用就减1 –
  • 如果引用次数是0 ,则释放内存
// 引用+1
const arr = [1, 2, 3, 4]
// 引用-1
arr = null

该算法的缺陷时,出现循环引用时,会导致内存泄漏

在这里插入图片描述
如上,即使执行o1 = null 和 o2 = null,o1和o2也不会被回收,因为引用还剩1

3.2 标记清除法

现代浏览器通用的大多是基于标记清除算法的某些改进算法,核心思路:

  • 标记清除算法将“不再使用的对象”定义为“无法达到的对象”
  • 就是从根部(在JS中就是全局对象)出发定时扫描内存中的对象,凡是能从根部到达的对象,都是还需要使用的
  • 那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收

在这里插入图片描述
对引用计数的循环引用问题,标记清除算法就不会有这个问题,和上图类似,执行o1 = null 和 o2 = null后,o1和o2就是一个不可达的状态了

4、闭包

4.1 定义

一个函数对周围状态的引用捆绑在一起,且内层函数中访问到其外层函数的作用域,就是闭包,简单说:闭包 = 内层函数 + 外层函数的变量,如下,内层函数f访问了外层函数outer的变量a,因此,内层函数和外层函数的变量a形成闭包

<body><script>function outer() {const a = 1function f() {console.log(a)}f()}outer()</script>
</body>

打个断点,然后刷新页面,卡在断点出后,可以看到作用域Scope里有个Closure,即闭包

在这里插入图片描述

闭包的作用:封闭数据,提供操作,外部也可以访问到函数内部的变量

<body><script>function outer() {const a = 1// 定义一个函数function f() {console.log(a)}// 返回一个函数,不是调用,加了小括号的f()是调用// 调用outer,就返回函数freturn f}// 函数const fun = outer()// 调用这个函数,就在外部拿到了outer函数内部的变量// 打印1fun()</script>
</body>

在这里插入图片描述

4.2 闭包的应用:实现数据的私有

实现统计函数的调用次数:

<body><script>let i = 0function fn() {console.log(++i)}</script>
</body>

能实现功能,但这个i 是个全局变量,很容易被修改

在这里插入图片描述

改一下,用局部变量和闭包:

<body><script>function count() {let i = 0function fn() {// 这里当然也可以简写成console.log(++i)i++console.log(i)}return fn}const fun = count()</script>
</body>

在这里插入图片描述
这样就实现了数据私有,无法直接修改,当然你别说这调用fun函数不还是修改了,这里体现了是不能被直接随意修改,fun函数里,你可以自定义权限校验代码,允许条件满足时再改

在这里插入图片描述

可以看出,局部变量i即使函数执行完也没有被回收,这也契合了标记清除算法的原理:从根部对象(JS的全局对象)出发,有一条引用链可达,因此不被回收,那既然这样,也就看出了闭包的另一个风险:可能导致内存泄漏(因为全局变量页面关闭时回收,那就可能存在一条一直可达的引用链)

5、变量提升

变量提升是JS中比较奇怪的现象,它允许在变量声明之前即被访问,当然仅存在于var声明变量

<body><script>// undefinedconsole.log(num)var num = 10</script>
</body>
<body><script>// 报错 Cannot access 'num' before initializationconsole.log(num)let num = 10</script>
</body>

变量提升,是指在代码执行前,内部会把当前作用域下,所有var声明的变量,提到当前作用域的最前面,只提升声明的代码,不提升赋值的代码,因此,就出现了上面的undefined,上面的代码,在变量提升后,其实就是下面的代码:

<body><script>// undefinedvar numconsole.log(num)num = 10</script>
</body>

JS变量提升的过程:

  • 先把var 变量提升到当前作用域于最前面
  • 只提升变量声明, 不提升变量赋值
  • 然后依次执行代码

如下,变量提升,是提到当前作用域的前面,var num的作用域是fn函数,而这里是全局作用域

<body><script>function fn() {// undefinedconsole.log(num)var num = 10}fn()// 这里就会报错了,num is not defined// 变量提升,是提到本作用域的前面,var num的作用域是fn函数,而这里是全局作用域console.log(num)</script>
</body>

总结:

  • 变量在未声明即被访问时会报语法错误,但var声明的变量,在声明之前即被访问,变量的值为 undefined,并不会报错
  • let/const 声明的变量不存在变量提升
  • 变量提升出现在相同作用域当中
  • 当然,实际开发推荐先定义再使用,不建议使用var声明变量

相关文章:

【JavaScript】二十九、垃圾回收 + 闭包 + 变量提升

文章目录 1、作用域1.1 局部作用域1.2 全局作用域1.3 作用域链 2、JC垃圾回收机制♻️3、GC算法3.1 引用计数法3.2 标记清除法 4、闭包4.1 定义4.2 闭包的应用&#xff1a;实现数据的私有 5、变量提升 1、作用域 即一个范围&#xff0c;离开了这个范围&#xff0c;这个变量就不…...

【从零开始学习RabbitMQ | 第一篇】从异步通信到交换机

目录 前言 1.什么是RabbitMQ&#xff1f; 2.同步调用的优缺点 3.异步调用的优缺点 3.1优点&#xff1a; 3.2异步调用的问题是什么&#xff1f; 4技术选型 4.1AMQP协议就是&#xff1a; 4.2kafka和RabbitMQ的使用场景 5.安装RabitMq 6.rabitmq的整体架构 7.RabibtM…...

100个常用的DeepSeek指令

日常生活类&#xff08;20个&#xff09; 1. 新闻解读&#xff1a;请为我解读今天的热点新闻。 2. 天气查询&#xff1a;请查询……的天气并推荐着装。 3. 旅行攻略&#xff1a;请制定前往……的旅行攻略。 4. 菜谱生成&#xff1a;请生成……菜的具体做法。 5. 解决方案&…...

AI(学习笔记第二课) 使用langchain进行AI开发

文章目录 AI(学习笔记第二课) 使用langchain进行AI开发学习内容&#xff1a;1. 使用背景2.创建python&#xff08;pycharm community版&#xff09;开发环境并连接deepseek2.1 创建python&#xff08;pycharm community版&#xff09;开发环境2.2 创建python工程2.3 写入初始py…...

基于Jenkins的DevOps工程实践之Jenkins共享库

文章目录 前言Jenkins共享库结构1、共享库演示2、知识点补充3、实践使用共享库格式化输出日志4、groovy基础语法4.1、 什么是 Groovy&#xff1f;4.2、groovy特点4.3、运行方法4.4、标识符4.5、基本数据类型4.5.1、string类型4.5.2、list类型 4.6、函数使用4.7、正则表达式 5、…...

使用Qt自带的Qt assistant时如何添加需要查看的文档

当我们双击打开Qt Assistant时 左边目录栏只有自带的帮助文档&#xff0c;所以需要添加要查看的文档 点击左上角Edit中的Preferences&#xff0c;点击add 找到qdoc文件夹 全选里面的内容 点击Apply 点击ok 左边的目录栏就出现所有这个版本的Qt有关的文档啦...

基于网络爬虫+Spark+Hadoop等大数据和SpringBoot技术实现的的汽车行业大数据分析与可视化平台系统(源码+论文+PPT+部署文档教程等)

博主介绍&#xff1a;CSDN毕设辅导第一人、全网粉丝50W,csdn特邀作者、博客专家、腾讯云社区合作讲师、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围…...

日本IT|AI应用工程师主要工作内容以及职业前景解析

1. 主要工作内容 AI应用工程师是&#xff1a; 类别具体工作内容常见工具需求分析和业务部门沟通&#xff0c;明确「用AI解决什么问题」PowerPoint, Excel, Miro模型选型与微调用现成AI&#xff08;如BERT、YOLOv8、Stable Diffusion等&#xff09;做Fine-TuningPython (PyTor…...

Soft Mask(软遮罩)技术

一、概述 Soft Mask是一种技术或工具&#xff0c;主要用于实现平滑的边缘遮罩效果。它在不同的应用领域有不同的实现和定义 1.在Unity UI设计中 SoftMask是一款专为Unity设计的高级遮罩工具&#xff0c;它突破了传统Mask的限制&#xff0c;提供了更为灵活和细腻的UI遮罩解决方案…...

ESP32开发之freeRTOS的互斥量

什么是互斥量互斥量的应用场合互斥量的API函数基本代码结构互斥量使用举例递归锁递归锁举例总结什么是互斥量 在freeRTOS中,多个任务访问一块共享资源,会产生竞争现象。 比如马路上只有一个很早以前的电话亭,A、B都想要打电话,然后他们就开始打架了。但是如果A先进去了然…...

K8s 资源分类

K8s 资源分类图谱 内置资源的分类 1、工作负载相关&#xff1a; Pod&#xff1a;最小的部署单元&#xff0c;包含一个或多个容器。 Deployment&#xff1a;管理无状态应用的副本和滚动更新。 StatefulSet&#xff1a;适用于有状态应用&#xff08;如数据库&#xff09;&#…...

Python连接云端服务器:基于Paramiko库的实践与问题剖析

引言 在软件开发与运维场景中&#xff0c;借助Python连接云端服务器进行操作极为常见。Paramiko库作为实现SSHv2协议的有力工具&#xff0c;为Python与云端服务器的交互搭建了桥梁。本文将深入介绍使用Paramiko连接云端Linux服务器的方法&#xff0c;并剖析过程中可能遭遇的问…...

基于 Flask的深度学习模型部署服务端详解

基于 Flask 的深度学习模型部署服务端详解 在深度学习领域&#xff0c;训练出一个高精度的模型只是第一步&#xff0c;将其部署到生产环境中&#xff0c;为实际业务提供服务才是最终目标。本文将详细解析一个基于 Flask 和 PyTorch 的深度学习模型部署服务端代码&#xff0c;帮…...

洛谷 P1850 [NOIP 2016 提高组] 换教室

题目传送门 前言 终于自己想出概率期望 d p dp dp 的状态了&#xff0c;但是依旧没能相对转移方程。&#xff08;招笑&#xff09; 暴力 这题部分分和特殊情况分给的挺多的&#xff0c;所以先拿部分分。 一、思路 先跑一边 F l o y d Floyd Floyd 最短路求出两点间最短距…...

C#生成二维码和条形码

C# 实现二维码和条形码生成&#xff1a;从入门到实战 文章目录 C# 实现二维码和条形码生成&#xff1a;从入门到实战一、引言二、准备工作2.1 开发环境搭建2.2 引入相关库 三、生成条形码3.1 条形码基本概念3.2 使用[ZXing.Net](https://ZXing.Net)生成条形码3.2.1 核心代码实现…...

【金仓数据库征文】金仓数据库 KES:MySQL 迁移实用指南

我们都知道&#xff0c;现在企业数字化转型那可是势在必行&#xff0c;数据库迁移这事儿就变得特别关键。金仓数据库的 KingbaseES&#xff08;简称 KES&#xff09;&#xff0c;就给咱从 MySQL 往 KES 迁移数据库提供了一套超好用的方案。下面咱就讲下 咋用金仓数据库来完成这…...

多态(c++详细版)

一.多态 1.1 多态的概念 多态(polymorphism)的概念&#xff1a;通俗来说&#xff0c;就是多种形态。多态分为编译时多态(静态多态)和运⾏时多态(动态多态)&#xff0c;这⾥我们重点讲运⾏时多态&#xff0c;编译时多态(静态多态)和运⾏时多态(动态多态)。编译时多态(静态多态)主…...

内存泄漏系列专题分析之八:高通相机CamX内存泄漏内存占用分析--通用ION(dmabuf)内存拆解

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:内存泄漏系列专题分析之七:高通相机CamX--Android通用ION(dmabuf)内存分配和释放原理 这一篇我们开始讲: 内存泄漏系列专题分析之八:高通相机CamX内存泄漏&内存占用分析--通用ION(dmabuf)内…...

后端项目进度汇报

项目概述 本项目致力于构建一个先进的智能任务自动化平台。其核心技术是一套由大型语言模型&#xff08;LLM&#xff09;驱动的后端系统。该系统能够模拟一个多角色协作的团队&#xff0c;通过一系列精心设计或动态生成的处理阶段&#xff0c;来高效完成各种复杂任务&#xff…...

数据结构——二叉树和堆(万字,最详细)

目录 1.树 1.1 树的概念与结构 1.2 树相关的术语 1.3 树的表示法 2.二叉树 2.1 概念与结构 2.2 特殊的二叉树 2.2.1 满二叉树 2.2.2 完全二叉树 2.3 二叉树存储结构 2.3.1 顺序结构 2.3.2 实现顺序结构二叉树 2.3.2.1 堆的概念与结构 2.3.2. 2 堆的插入与删除数据…...

MATLAB基于格拉姆角场与2DCNN-BiGRU的轴承故障诊断模型

本博客来源于CSDN机器鱼&#xff0c;未同意任何人转载。 更多内容&#xff0c;欢迎点击本专栏目录&#xff0c;查看更多内容。 目录 0 引言 1 格拉姆角场原理 2 2DCNN-BiGRU网络结构 3 应用实例 3.1 数据准备 3.2 格拉姆角场数据提取 3.3 网络模型搭建-重中之重 3.4 …...

正点原子IMX6U开发板移植Qt时出现乱码

移植Qt时出现乱码 1、前言2、问题3、总结 1、前言 记录一下正点原子IMX6U开发板移植Qt时出现乱码的解决方法&#xff0c;方便自己日后回顾&#xff0c;也可以给有需要的人提供帮助。 2、问题 用正点原子IMX6U开发板移植Qt时移植Qt后&#xff0c;sd卡里已经存储了Qt的各种库&…...

JVM局部变量表和操作数栈的内存布局

局部变量表和操作数栈 首先看一段Java源码 public class Add_Sample{public int add(int i, int j){int k 100;int result i j k;return result;}public static void main(String[] args){int result new Add_Sample().add(10,20);System.out.println(result);} }使用ja…...

Mockoon 使用教程

文章目录 一、简介二、模拟接口1、Get2、Post 一、简介 1、Mockoon 可以快速模拟API&#xff0c;无需远程部署&#xff0c;无需帐户&#xff0c;免费&#xff0c;跨平台且开源&#xff0c;适合离线环境。 2、支持get、post、put、delete等所有格式。 二、模拟接口 1、Get 左…...

使用 IDEA + Maven 搭建传统 Spring MVC 项目的详细步骤(非Spring Boot)

搭建Spring MVC项目 第一步&#xff1a;创建Maven项目第二步&#xff1a;配置pom.xml第三步&#xff1a;配置web.xml第四步&#xff1a;创建Spring配置文件第五步&#xff1a;创建控制器第六步&#xff1a;创建JSP视图第七步&#xff1a;配置Tomcat并运行目录结构常见问题解决与…...

以下是在 Ubuntu 上的几款PDF 阅读器,涵盖轻量级、功能丰富和特色工具:

默认工具&#xff1a;Evince&#xff08;GNOME 文档查看器&#xff09; 特点&#xff1a;Ubuntu 预装&#xff0c;轻量快速&#xff0c;支持基本标注和书签。 安装&#xff1a;已预装&#xff0c;或手动安装&#xff1a; sudo apt install evince功能全面&#xff1a;Okular&…...

3.2.3 掌握RDD转换算子 - 4. 按键归约算子 - reduceByKey()

在本节课中&#xff0c;我们深入学习了Spark RDD的reduceByKey()算子。reduceByKey()主要用于处理元素为(key, value)形式的RDD&#xff0c;能够将相同key的元素聚集并合并&#xff0c;最终返回一个新RDD&#xff0c;其元素类型与原RDD保持一致。通过案例演示&#xff0c;我们首…...

AI领域的MCP(Model-Centric Paradigm)

1. 什么是MCP&#xff08;Model-Centric Paradigm&#xff09;&#xff1f; MCP&#xff08;Model-Centric Paradigm&#xff09;是人工智能开发中的一种核心理念&#xff0c;强调以模型的优化与改进作为主要驱动因素来提升AI系统的表现。在MCP模式下&#xff0c;开发者专注于…...

Pandas比MySQL快?

知乎上有人问&#xff0c;处理百万级数据&#xff0c;Python列表、Pandas、Mysql哪个更快&#xff1f; Pands是Python中非常流行的数据处理库&#xff0c;拥有大量用户&#xff0c;所以拿它和Mysql对比也是情理之中。 实测来看&#xff0c;MySQL > Pandas > Python列表…...

模拟内存管理

文章目录 1. 实验六&#xff1a;内存管理2. 记录内存空间使用情况2.1 全局参数2.2 内存空间相关参数2.3 关键结构体定义2.4 内存系统初始化 3. 记录空闲分区3.1 采用位图的方式记录物理内存中的空闲帧3.1.1 记录方式3.1.2 举例分析 3.2 主要操作3.2.1 初始化空闲帧&#xff1a;…...