javaScript关于闭包的理解

news2024/11/24 13:01:30

首先在了解闭包之前,我们要了解一下环境和作用域

1.环境和作用域

日常生活中我们生活的环境由周边建设如公园,小区,超市构成的。这就构成了环境

在计算机当中环境就是一块内存的数据。

环境是有作用范围的,eg:武汉周边的建设一般只服务武汉生活的人们,这就是作用域。作用域是闭包的基础

环境存在的价值是被需要,当环境不被需要的时候就会被回收

在js中全局的环境是不会被回收的,全局环境在很多时候是被依赖的

1)  函数被执行后里面的环境变量将会从内存中删除。下面函数在每次执行后将删除函数内部的 total 变量。
function count(){
let total=0
}
count()

函数在每次执行的时候都会创建一个环境,都会产生一个新的内存地址 【函数没有调用就不会开辟内存空间或者称之为环境】

作用域链只向上查找,找到全局 window 即终止,应该尽量不要在全局作用域中添加变量。

2)   如果子函数被使用时父级环境将被保留
 function mushu () {
    let n = 1
    return function sum () {  // 当有return之后,里面的数据就在一直被使用 就不会被摧毁
      let m = 1
      return function show () {
        console.log(++m) // 2 3 
        console.log('n', ++n) // 2 3 
      }
      show()
    }
  }
  let a = mushu()()
  a()
  a()
// 调用了两次,被外部引用只会数据不会被销毁,所以一直进行了累加

函数定义的数据,其作用域是函数及其子函数,子函数中的数据不会向父级进行传递,向父级进行传递,有可能会覆盖父级的数据

3)    let/const

使用 let/const 可以将变量声明在块作用域中(放在新的环境中,而不是全局中)

let 块作用域中

var 函数作用域护着

{
	let a = 9;
}
console.log(a); //ReferenceError: a is not defined
if (true) {
	var i = 1;
}
console.log(i);//1

//**************************其他例子**********************
let arr = [];
for (let i = 0; i < 10; i++) {
	arr.push((() => i));
}
console.log(arr[3]()); //3 如果使用var声明将是10

2.闭包

闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。

直观的说就是形成一个不销毁的栈环境。

闭包可以实现属性的私有化

3.闭包使用

闭包指子函数可以访问外部作用域变量的函数特性,即使在子函数作用域外也可以访问。如果没有闭包那么在处理事件绑定,异步请求时都会变得困难。

  • JS 中的所有函数都是闭包
  • 闭包一般在子函数本身作用域以外执行,即延伸作用域
eg:1
 let lessons = [
    {
      title: "媒体查询响应式布局",
      click: 89,
      price: 12

    },
    {
      title: "媒体查询响应式布局",
      click: 84,
      price: 120

    }, {
      title: "Flex布局",
      click: 68,
      price: 90

    }, {
      title: "你好呀!!",
      click: 15,
      price: 34

    },
    {
      title: "hello world",
      click: 89,
      price: 67
    }
  ]

  function bwtween (a, b) {
    return function (v) {   // 这里的v 就是数组里面的元素  
      //function (v)这是between函数的子函数 利用闭包特性可以访问到父级的变量
      return v.price >= a && v.price <= b
    }
  }
  console.table(lessons.filter(bwtween(50, 100)));
eg2:实现属性私有
// 普通形式 统计函数调用的次数
  let i = 0
  function fn () {
    i++
    console.log(`函数调用了${i}次`)
  }

function count () {
    let i = 0
    function fn () {
      i++
      console.log(`函数调用了${i}次`)
    }
    return fn
  }
  const fun = count()

4.闭包内存泄漏的问题

 function fn () {
    let count = 1
    function fun () {
      count++
      console.log(`函数被调用了${count}次`)  //函数被调用了2次 函数被调用了3次
    }
    return fun
  }
  // res是一个全局变量,代码执行完成之后不会立即销毁,并且res调用了fn函数,fn调用了fun,fun里面使用到了count,count被引用就不会被回收,所以一直存在
  // 此时:闭包引起了内存泄露
  const res = fn()  
  
  res()   
  res()
//注意不是所有的内存泄露都要手动回收,react中的很多闭包不能被回收

上级作用域会为函数保存数据,从而造成的如下所示的内存泄漏问题

<body>
  <div desc="annanan~~">周日了</div>
  <div desc="hahahahah!!!">我也不知道!! </div>
</body>
<script>
  let mushu = document.querySelectorAll("div")
  mushu.forEach(function (item) {
    let desc = item.getAttribute("desc")
    item.addEventListener("click", function () { // 这个函数是事件处理函数,是一直存在的,
      // 根据闭包的特性父级作用域的元素也会一直存在,
      console.log(item.getAttribute("desc"))  // getAttribute 属性名
      console.log(item)
    })
  })

 

下面通过清除不需要的数据解决内存泄漏问题

<body>
  <div desc="annanan~~">周日了</div>
  <div desc="hahahahah!!!">我也不知道!! </div>
</body>
<script>
  let mushu = document.querySelectorAll("div")
  mushu.forEach(function (item) {
    let desc = item.getAttribute("desc")
    item.addEventListener("click", function () { // 这个函数是事件处理函数,是一直存在的,
      // 根据闭包的特性父级作用域的元素也会一直存在,
      // console.log(item.getAttribute("desc"))  // getAttribute 属性名
      console.log(desc)
      console.log(item)
    })
    item = null
  })
</script>

5.闭包一定存在内存泄露吗?闭包一定有return?

闭包可能引起内存泄露,但是不一定所以的内存泄露都会被回收

答案是不一定

闭包经常被函数包裹,里面的变量是局部的,外面不能直接使用,所以我们会用到return,将函数返回出去,外部可以使用内部的变量,但是不能修改里面的变量。

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

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

相关文章

YOLOv8 Tensorrt部署详细介绍(小白从0到1,不会你砍我)

下载YOLOv8项目和Tensorrt部署项目 git clone https://github.com/xiaocao-tian/yolov8_tensorrt.git git clone https://github.com/ultralytics/ultralytics.git 下载yolov8s模型 在YOLOv8项目中新建weights文件夹&#xff0c;将yolov8s.pt放入 运行tensorrt项目中gen_wts…

RabbitMQ 介绍与 SpringBootAMQP使用

一、MQ概述 异步通信的优点&#xff1a; 耦合度低吞吐量提升故障隔离流量削峰 异步通信的缺点&#xff1a; 依赖于Broker的可靠性、安全性、吞吐能力架构复杂&#xff0c;业务么有明显的流程线&#xff0c;不方便追踪管理 什么是的MQ MQ&#xff08;Message Queue&#xf…

选择适合建筑公司的企业网盘平台

随着城市化进程的加速&#xff0c;越来越多的人开始关注乡村生活品质。Z公司以其标准化产品和优质资源整合&#xff0c;为回乡建房人群提供了一种全新的、高品质的整体解决方案。 Z公司深入调研了10W的回乡建房人群需求&#xff0c;组建了设计、工艺、供应链方面的专家团队&…

KUKA机器人通过直接输入法设定负载数据和附加负载数据的具体操作

KUKA机器人通过直接输入法设定负载数据和附加负载数据的具体操作 设置背景色: 工具负载数据 工具负载的定义: 工具负载数据是指所有装在机器人法兰上的负载。它是另外装在机器人上并由机器人一起移动的质量。需要输入的值有质量、重心位置、质量转动惯量以及所属的主惯性轴。…

边坡安全监测系统:守护边坡稳定的重要工具

在工程建设中&#xff0c;边坡安全监测系统一直被认为是掌握边坡安全及其支护结构维护决策系统的关键支撑条件。这一系统的主要目的在于确定边坡结构的稳定性&#xff0c;监控支护结构的承载能力、运营状态和耐久性能&#xff0c;并对边坡稳定性进行实时监控。 一、边坡安全监测…

CTF学习笔记——PWN(入门)

文章目录 [toc] CTF学习笔记——PWN&#xff08;入门&#xff09;PWN基础概念NC题[HGAME 2023 week1]test_nc 栈溢出[HNCTF 2022 Week1]easyoverflow 伪随机数[SWPUCTF 2022 新生赛]Darling 待补充待补充 CTF学习笔记——PWN&#xff08;入门&#xff09; &#x1f680;&#x…

python常用库之数据库orm框架之SQLAlchemy

文章目录 python常用库之数据库orm框架之SQLAlchemy一、什么是SQLAlchemySQLAlchemy 使用场景 二、SQLAlchemy使用SQLAlchemy根据模型查询SQLAlchemy SQL 格式化的方式db_session.query和 db_session.execute区别实测demo 总结&#xff1a;让我们留意一下SQLAlchemy 的 lazy lo…

电流,功率监控芯片INA226应用(基于STM32工程)

一芯片介绍 INA226是具有I2C™或SMBUS兼容接口的电流分流器和功率监控器。该设备同时监视并联电压降和总线电源电压。可编程的校准值&#xff0c;转换时间和平均值与内部乘法器结合使用&#xff0c;可以直接读取以安培为单位的电流和以瓦特为单位的功率。INA226感应共模总线电…

Spring【@Resource、@Autowired+lombook+Bean的生命周期】

Resource 和 Autowired 的区别 在Spring中找Bean的两种方式&#xff1a;①先根据类型查找②再根据名称查找 Autowired先根据类型查找&#xff0c;再根据名称查找【根据上述查找结果不唯一&#xff0c;再添加一个 Qualifier(value“”)&#xff0c;就可以查找】 Resource先根据名…

Spring Cloud Gateway2之断言Predicate详解

文章目录 1. 前言2. Spring Cloud Gateway断言的种类及各自功能2.1. Path断言 PathRoutePredicateFactory2.2.Method断言 MethodRoutePredicateFactory2.3.Header断言 HeaderRoutePredicateFactory2.4.Host断言 HostRoutePredicateFactory2.5.Query断言 QueryRoutePredicateFac…

【C++】unordered_set和unordered_map介绍及使用【附OJ题】

目录 一、unordered_set和unordered_map的介绍和使用 1、介绍 2、使用及与set和map的区别 3、O&#xff08;logN&#xff09;和 O&#xff08;1&#xff09;的效率对比 二、力扣OJ题 1、重复N次的元素 2、两个数组的交集 一、unordered_set和unordered_map的介绍和使用…

AI+Social Power,开创营销新纪元 | 2023数说故事年度社媒营销盛会,10月13日邀您共同见证

尊敬的嘉宾&#xff1a; AIGC成为2023年最热门的关键词之一&#xff0c;且以惊人的速度赢得了“圈层共识”&#xff0c;各行业都在探索如何利用AI技术创造更多可能性。尤其在社媒营销领域&#xff0c;AIGC的应用已成为势不可挡的趋势&#xff1a;品牌们用AI造新品&#xff0c;…

OpenHarmony嵌套类对象属性变化:@Observed装饰器和@ObjectLink装饰器

上文所述的装饰器仅能观察到第一层的变化&#xff0c;但是在实际应用开发中&#xff0c;应用会根据开发需要&#xff0c;封装自己的数据模型。对于多层嵌套的情况&#xff0c;比如二维数组&#xff0c;或者数组项class&#xff0c;或者class的属性是class&#xff0c;他们的第二…

子组件跳转父组件

描述&#xff1a;父组件Form.vue 点击关联&#xff0c;弹出子组件importForm.vue 选中一条数据之后&#xff0c;点击确定按钮&#xff0c;关闭子组件importForm.vue&#xff0c;将子组件的内容显示在父组件Form.vue中 选中第一条数据&#xff0c;点击确定 父组件对应的工作内容…

Java源码分析(三)ArrayList

ArrayList是我们经常用到的一个集合类&#xff0c;那么本篇我们一起学习下ArrayList的源码。 一、创建ArrayList 首先&#xff0c;我们从创建ArrayList开始。如下代码&#xff0c;创建一个空的ArrayList&#xff1a; List<String> list new ArrayList<>(); 看下…

Java中的锁与锁优化技术

文章目录 自旋锁与自适应自旋锁消除锁粗化轻量级锁偏向锁重量级锁 自旋锁与自适应自旋 自旋锁是一种锁的实现机制&#xff0c;其核心思想是当一个线程尝试获取锁时&#xff0c;如果锁已经被其他线程持有&#xff0c;那么这个线程会在一个循环中不断地检查锁是否被释放&#xf…

长效和短效HTTP:哪个适合爬虫的代理类型?

在进行网络爬虫任务时&#xff0c;选择适合的代理类型对爬虫的效率和稳定性至关重要。长效和短效HTTP代理是两种常见的代理类型&#xff0c;它们各具特点和适用场景。本文将为您分享长效和短效HTTP代理的区别以及选择适合爬虫的代理类型的实用技巧&#xff0c;帮助您提升爬虫效…

Linux Ftrace介绍

文章目录 一、简介二、内核函数调用跟踪参考链接&#xff1a; 一、简介 Ftrace 是 Linux 官方提供的跟踪工具&#xff0c;在 Linux 2.6.27 版本中引入。Ftrace 可在不引入任何前端工具的情况下使用&#xff0c;让其可以适合在任何系统环境中使用。 Ftrace 可用来快速排查以下相…

一个tomcat下如何部署多个项目?

1、不修改端口&#xff0c;部署多个项目 清楚tomcat目录结构的应该都知道&#xff0c;项目包是放在webapps目录下的&#xff0c;那能否在同一个tomcat的webapps目录下运行多个不同项目呢&#xff1f; 答案是可以的。 1、将多个项目包放入webapps文件夹下 2、修改conf下的serv…

10.8作业

自己封装一个矩形类(Rect)&#xff0c;拥有私有属性:宽度(width)、高度(height)&#xff0c; 定义公有成员函数: 初始化函数:void init(int w, int h) 更改宽度的函数:set_w(int w) 更改高度的函数:set_h(int h) 输出该矩形的周长和面积函数:void show() #include <io…