js基础之闭包

2023-11-17

作为前端开发,闭包是时时刻刻都在使用的,理解闭包是十分重要的,下面从闭包的定义,使用场景,及优缺点进行总结,帮助大家更好的理解闭包。

什么是闭包

引用自 MDN关于闭包的描述

闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建。

闭包 = 函数 + 函数内部能访问的所有变量

换句话说:闭包是指在函数内部定义的函数可以访问到外部函数的变量,即使外部函数已经执行完毕退出了,内部函数仍然可以访问到外部函数的变量。如下

function outerFunction() {
  const outerVariable = "Hello, world!";

  function innerFunction() {
    console.log(outerVariable);
  }

  return innerFunction;
}

const closure = outerFunction();
closure(); // 输出 "Hello, world!"

使用场景

封装私有变量

// count变量只能在createCounter内部使用
function createCounter() {
  let count = 0;
  return function() {
    count++;
    console.log(count);
  }
}

延迟执行

function delay(func, time) {
  return function() {
    setTimeout(func, time);
  }
}

const delayedFunc = delay(function() {
  console.log('Hi!');
}, 1000);

delayedFunc(); // 1 秒后输出 "Hi!"
// delay 函数返回一个内部函数,该函数在被调用时才会执行 func 函数,
// 并且在 time 毫秒后才会执行,达到了延迟执行的目的

常说的防抖节流中

// 防抖
function debounce(fn,delay) {
  let timer = null
  return function() {
    let args = arguments
    if(timer) {
      clearTimeout(timer)
    }
    timer = setTimeout(()=>{
      fn.apply(this,args)
    },delay)
  }
}
// debounce 函数返回一个内部函数,该函数在被连续调用时会清除之前的定时器,
// 延迟一段时间后再执行 func 函数。
// 由于需要在延迟执行的过程中访问外部变量 timer,因此使用了闭包
// 节流
function throttle(fn,delay) {
  let record = Date.now()
  return function(...args) {
    let now = Date.now()
    const interval = now - record
    if(interval>delay) {
      fn(...args)
      record = now
    }
  }
}
// 由于需要在内部函数中保存上一次执行的时间record,因此使用了闭包。

缓存数据

function memoize(func) {
  const cache = {};
  return function(arg) {
    if (arg in cache) {
      return cache[arg];
    } else {
      const result = func(arg);
      cache[arg] = result;
      return result;
    }
  }
}

function expensiveCalculation(n) {
  console.log('Calculating...');
  return n * 2;
}

const memoizedCalculation = memoize(expensiveCalculation);
memoizedCalculation(5); // 输出 "Calculating..." 和 10
memoizedCalculation(5); // 直接输出 10,不再计算

模块化开发

const module = (function() {
  let privateVar = 0;
  function privateFunc() {
    console.log('Private function');
  }
  return {
    publicVar: 1,
    publicFunc: function() {
      console.log('Public function');
    }
  }
})();

console.log(module.publicVar); // 输出 1
module.publicFunc(); // 输出 "Public function"
console.log(module.privateVar); // 输出 undefined
module.privateFunc(); // 报错,因为无法访问私有函数
// 使用立即执行函数和闭包的方式实现了模块化开发,将私有变量和函数封装在了内部,
// 对外暴露了公共接口,提高了代码的可维护性

实现回调函数

function fetchData(url, callback) {
  fetch(url)
    .then(response => response.json())
    .then(data => callback(data))
    .catch(error => console.error(error));
}

function displayData(data) {
  console.log(data);
}

fetchData('https://jsonplaceholder.typicode.com/todos/1', displayData);
// 将函数作为参数传递给另一个函数,并在需要的时候调用

优点

一句话:私有化数据,并且在私有化数据的基础上可以保存数据

问题

  1. 内存泄漏

    闭包会导致一些变量一直被引用,而无法被垃圾回收器回收,从而导致内存泄漏。一般来说,在使用闭包时,要确保不再需要某个变量时,要将其设置为null,以便垃圾回收器回收。

  2. 性能问题

    由于闭包会在函数执行完毕后继续占用内存,因此使用闭包会对性能造成一定的影响。在需要频繁调用的函数中,使用闭包可能会导致函数执行速度变慢。

综上,我们在使用闭包的时候,需要注意避免闭包中的变量一直被引用,可以在不需要使用闭包的时候,将闭包设置为null,以便垃圾回收器回收,避免内存占用过高的问题。

补充:垃圾回收机制

垃圾回收机制是一种自动化的内存管理技术,用于检测和回收不再被程序使用的内存。在 JavaScript 中,垃圾回收机制是由 JavaScript 引擎自动执行的,程序员无需手动管理内存。

垃圾回收机制的基本原理是标记清除和引用计数

  1. 标记清除:垃圾回收器会在内存中维护一个“根集合”,它包含了一些全局变量和当前调用栈中的变量。垃圾回收器会从根集合开始遍历所有变量,并标记它们是否可达。不可达的变量就会被回收。
  2. 引用计数:垃圾回收器会维护每个变量的引用计数,即记录有多少个变量引用了该变量。当引用计数为 0 时,说明该变量不再被使用,就会被回收。
    在实际应用中,大多数 JavaScript 引擎采用标记清除算法,辅以引用计数算法来处理循环引用的情况。

在 JavaScript 中,垃圾回收机制的具体实现由 JavaScript 引擎负责。不同的JavaScript 引擎有不同的垃圾回收机制,例如 V8 引擎采用了分代垃圾回收机制,将内存分为新生代和老生代两个区域,并对它们采用不同的垃圾回收策略。

总之,垃圾回收机制是一种自动化的内存管理技术,可以帮助程序员避免内存泄漏和内存溢出等问题,提高代码的可靠性和性能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

js基础之闭包 的相关文章

随机推荐

  • java并发编程笔记(三)--管程(二)

    习题 卖票 请改正 public class ExerciseSell public static void main String args 2000张票 TicketWindow ticketWindow new TicketWindo
  • Redis - WRONGTYPE Operation against a key holding the wrong kind of value

    用RedisTemplate把数据存入Redis key值为物料编码 value值为对应对象 但相同物料编码对应的对象不一定唯一故采用Set for int i 0 i lt retrospectiveBomSbomtList size i
  • 分布式系统的一致性级别划分及Zookeeper一致性级别分析

    最近在研究分布式系统的一些理论概念 例如关于分布式系统一致性的讨论 看了一些文章我有一些不解 大多数对分布式系统一致性的划分是将其分为三类 强一致性 顺序一致性以及弱一致性 强一致性 Strict Consistency 也称为 原子一致性
  • Vuex的五个核心属性

    Vuex的五个核心概念 本文参考自Vue文档 说的非常详细 建议看文档 Vuex是什么 VueX 是一个专门为 Vue js 应用设计的状态管理架构 统一管理和维护各个vue组件的可变化状态 你可以理解成 vue 组件里的某些 data V
  • svg格式的图片转化为 png 格式

    下载并使用插件插件 save svg as png import saveSvg from save svg as png let path url t new Date getTime const parser new DOMParser
  • (全网最详细)如何在docker里搭建mmdetection环境并封装成镜像

    目录 前言 1 理解docker 2 搭建过程 2 1 创建基础镜像 2 2 构建容器 2 3 进入容器 2 4 搭建环境 2 5 测试 2 6 提交 3 小结 前言 目的 由于一个AI比赛需要提交算法Docker 捣鼓好几天终于有点眉目
  • Vue.js快速入门 (cdn引入)

    文章目录 一 Vue基础 1 1 渐进式框架 1 2 第一个Vue程序 1 3 el 挂载点 1 4 data 数据对象 二 Vue 指令 2 1 v text 文本值 2 2 v html 标签元素 2 3 v on 绑定事件 2 4 v
  • 零基础入门网络安全必看的5本书籍(附书单pdf)

    作为一个Java转行网络安全的过来人 我深知自学时的种种不易 同时也经常有粉丝朋友问我 刚入门应该怎么学 有哪些书籍推荐等问题 今天我就把我自己的学习书单分享给大家 希望对大家有帮助 一 5本必读书籍 1 1 鸟哥的Linux私房菜 推荐理
  • Docker部署tomcat

    文章目录 1 下载Tomcat镜像 2 启动 3 进入Tomcat 1 下载Tomcat镜像 首先可以去官网查看想要下载的tomcat版本 https hub docker com tomcat 官方的使用 不推荐 官方文档解释 it 交互
  • Go1.21 速览:新内置函数 clear、min、max 和新标准库包 cmp!

    大家好 我是煎鱼 前面给大家分享了 Go1 21 正式不支持 macOS 10 13 和 10 14 的支持 吓得我赶紧把我的 2017 款的老爷机从 10 14 升成 13 4 感觉 mbp 已经变成了暖宝宝 今天给大家分享的是 Go 1
  • 自然辩证法(研究生)期末考试题库

    仅供参考 后果概不负责 第一讲 实际上就是科学与马克思主义哲学的纽带和桥梁 这就如同历史唯物主义是马克思主义哲学和各门社会科学的中间环节一样 A 社会学B 哲学C 科技与社会D 自然辩证法 答案 D 自然界 按照我们通常的理解 其内涵包括上
  • 【已解决】Hyperledger Fabric 2.3创建通道失败问题Channel creation failed

    简介 问题描述 在按照readthedocs教程进行超级账本框架 fabric区块链的学习过程中 到通道创建这一步一直失败 即无法成功运行 network sh up createChannel 出现的错误提示 直接去搜索这个segment
  • mc有无限火力的服务器ip,MC小游戏:起床战争-无限火力I(上)

    再次来到花雨庭 我径直走向起床战争 无限火力 这次陪同我的还有24 25和小9 钱猫 我 也来了 为什么把我说漏了 还有钱猫 钱猫 这还差不多 朝着无限火力的NPC点了一下 很快 就到了游戏大厅 25慌张地说道 你看这群人 要么是VIP 要
  • java实现将数据导出为word功能(文字,表格,图片的循环导出)

    1 配置文件的准备 1 导出功能实现所需要的pom文件
  • 高维空间最近邻逼近搜索算法评测

    高维空间最近邻逼近搜索算法评测 最近邻方法是机器学习中一个非常流行的方法 它的原理很容易理解 邻近的数据点是相似的数据点 更可能属于同一分类 然而 在高维空间中快速地应用最近邻方法 却是非常有挑战性的工作 全球最大的流媒体音乐服务商Spot
  • Intellij导入子项目时,maven列表子项目灰色不可用---解决方法

    导入子项目的module时 左侧project目录中有一个module图标右下角没有小蓝点 maven管理列表该module为灰色 表明未被管理 尝试几次后终于找到解决方案 贴一张调好过后的图 第一步 找到父项目 点击右键 选择Open M
  • 大话Stable-Diffusion-Webui-客制化主题(二)

    文章目录 前置知识 在gradio项目中使用客制化的主题 创建一个完整的Gradio主题 上传客制化主题至huggingface 笔者DIY的主题 接着 大话Stable Diffusion Webui 客制化主题 一 继续探讨下基于gra
  • 用python实现输出3位水仙花数

    3位水仙花数 是指一个三位整数 其各位数字的3次方和等于该数本身 例如 ABC是一个 3位水仙花数 则 A的3次方 B的3次方 C的3次方 ABC 请按照从小到大的顺序输出所有的3位水仙花数 请用 逗号 分隔输出结果 shuixianhua
  • 黑马程序员---类加载器

    android培训 java培训 期待与您交流 简要介绍什么是类加载器和类加载器的作用 Java虚拟机中可以安装多个类加载器 系统默认三个主要类加载器 每个类负责加载特定位置的类 BootStrap ExtClassLoader AppCl
  • js基础之闭包

    作为前端开发 闭包是时时刻刻都在使用的 理解闭包是十分重要的 下面从闭包的定义 使用场景 及优缺点进行总结 帮助大家更好的理解闭包 什么是闭包 引用自 MDN关于闭包的描述 闭包 closure 是一个函数以及其捆绑的周边环境状态 lexi