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

JavaScript 中的闭包的形成及使用场景

JavaScript 中的闭包

闭包(Closure) 是 JavaScript 中一个非常重要且独特的概念,它指的是 函数能够记住并访问其词法作用域内的变量,即使这个函数在其词法作用域之外执行。

通俗地说,闭包是 一个函数可以“记住”它在定义时的环境(包括变量和参数),即使这个函数在它定义时的作用域之外被调用,它仍然可以访问该作用域中的变量。

闭包的形成

当一个函数内部定义并返回了另一个函数时,并且这个内部函数引用了外部函数的变量,这就形成了闭包。闭包使得内部函数能够“记住”它定义时外部函数的变量,即使外部函数已经执行结束了,这些变量仍然可以被访问。

闭包的例子
function outer() {let counter = 0;return function inner() {counter++;console.log(counter);}
}const increment = outer();
increment(); // 输出: 1
increment(); // 输出: 2
increment(); // 输出: 3

在这个例子中:

  • outer 函数返回了 inner 函数,而 inner 函数引用了 outer 函数中的局部变量 counter
  • 即使 outer 函数已经执行完毕,inner 函数仍然能够访问和修改 counter,因为 inner 函数形成了一个闭包,保存了对 outer 函数作用域中变量的引用。

闭包的特性

  1. 函数可以记住它的词法作用域:即使外部函数已经返回,闭包中的函数仍然可以访问外部函数作用域中的变量。

  2. 局部变量的持久化:闭包中的局部变量不会在外部函数返回后被销毁,它们会被保留,直到没有任何闭包再引用它们为止。

  3. 数据封装:闭包可以模拟私有变量,避免外部直接访问或修改这些变量,只能通过闭包函数来操作它们。

闭包的使用场景

闭包的应用场景非常广泛,以下是一些常见的使用场景:

1. 模拟私有变量

JavaScript 中没有真正的私有变量,但闭包可以帮助实现类似的效果。通过闭包,可以创建只能通过特定函数访问和修改的变量,避免外部直接访问。

function createCounter() {let count = 0;return {increment: function() {count++;console.log(count);},decrement: function() {count--;console.log(count);}}
}const counter = createCounter();
counter.increment(); // 输出: 1
counter.increment(); // 输出: 2
counter.decrement(); // 输出: 1

在这个例子中,countcreateCounter 函数中的局部变量,外部无法直接访问它,只能通过 incrementdecrement 方法修改它的值。这种方式模拟了私有变量的行为。

2. 函数工厂

闭包可以用于创建返回不同功能的函数,类似于工厂模式。例如,可以创建多个配置不同的计数器:

function createCounter(start) {let count = start;return function() {count++;console.log(count);}
}const counter1 = createCounter(0);
const counter2 = createCounter(100);counter1(); // 输出: 1
counter1(); // 输出: 2
counter2(); // 输出: 101
counter2(); // 输出: 102

每次调用 createCounter 都会生成一个新的计数器实例,且每个计数器都能记住自己的初始值。

3. 回调函数和事件处理

闭包广泛应用于回调函数、事件处理等异步编程场景中。例如,在事件处理函数中,闭包可以保存外部函数的状态,并在事件触发时访问这些状态。

function setupEventListeners() {let name = 'Button clicked!';document.getElementById('myButton').addEventListener('click', function() {console.log(name); // 即使外部函数已执行完毕,仍然能访问 name});
}setupEventListeners();

即使 setupEventListeners 函数执行完毕后,点击按钮时仍然可以访问 name 变量,这是因为 addEventListener 的回调函数形成了闭包。

4. 防抖与节流

闭包常用于防抖和节流函数的实现,以保存计时器状态或限制函数执行频率。例如,防抖函数在用户停止输入一段时间后才执行,可以避免多次频繁的操作。

function debounce(fn, delay) {let timer = null;return function(...args) {clearTimeout(timer);timer = setTimeout(() => {fn.apply(this, args);}, delay);}
}const handleInput = debounce(function(event) {console.log('Input event triggered', event.target.value);
}, 500);document.getElementById('searchInput').addEventListener('input', handleInput);

在这个例子中,闭包用于保存 timer 变量的状态,使得每次用户输入时,timer 不会被销毁,从而实现防抖效果。

5. 缓存(记忆化)

闭包还可以用于缓存计算结果,提高函数的效率。例如,记忆化函数可以缓存已经计算过的结果,避免重复计算。

function memoize(fn) {const cache = {};return function(...args) {const key = JSON.stringify(args);if (cache[key]) {return cache[key];}const result = fn.apply(this, args);cache[key] = result;return result;}
}function slowFunction(num) {console.log('Expensive calculation...');return num * 2;
}const memoizedFunction = memoize(slowFunction);
console.log(memoizedFunction(5)); // 输出: Expensive calculation... 10
console.log(memoizedFunction(5)); // 输出: 10 (缓存结果,没有再计算)

在这里,闭包用于保存计算结果的 cache,当相同的参数再次传递时,直接返回缓存的结果。

闭包的优缺点

优点:
  1. 数据封装:闭包可以帮助创建私有变量,使得某些数据只能通过特定的函数进行访问和修改。
  2. 保持状态:闭包可以保持函数执行时的环境,使得外部函数返回后,依然能够访问和操作这些状态。
  3. 减少全局变量的使用:闭包可以避免使用全局变量,减少变量污染和命名冲突。
缺点:
  1. 内存占用:由于闭包持有外部函数作用域的引用,可能会导致内存得不到及时释放,增加内存消耗,甚至可能引发内存泄漏。
  2. 调试难度:闭包可能导致调试更加复杂,因为内部函数依赖外部的上下文环境,容易引发不可预料的行为。

总结

闭包是 JavaScript 中的一个强大特性,它允许函数在词法作用域之外保持对外部变量的引用。它常用于数据封装回调函数工厂函数防抖/节流等场景。虽然闭包非常强大,但在使用时也要注意内存管理,避免不必要的内存占用和泄漏。

相关文章:

JavaScript 中的闭包的形成及使用场景

JavaScript 中的闭包 闭包(Closure) 是 JavaScript 中一个非常重要且独特的概念,它指的是 函数能够记住并访问其词法作用域内的变量,即使这个函数在其词法作用域之外执行。 通俗地说,闭包是 一个函数可以“记住”它在…...

后端返回内容有换行标识,前端如何识别换行

<br/>的话 用 v-html \n 可以用css样式 white-space: pre-wrap 后端返回结果 前端...

服务器被挂马,导致网站首页被更改怎么解决

当服务器被挂马并导致网站首页被篡改时&#xff0c;说明服务器或网站的安全性遭到破坏。为了修复并防止未来的攻击&#xff0c;你可以按照以下步骤进行操作&#xff1a; 1. 立即下线网站 目的&#xff1a;防止恶意软件进一步传播&#xff0c;保护用户数据和防止攻击者继续对网…...

Android 利用OSMdroid开发GIS

1、地址 Github地址&#xff1a;https://gitee.com/mirrors/osmdroid Git地址&#xff1a; GitCode - 全球开发者的开源社区,开源代码托管平台 Git下载包地址&#xff1a;Releases osmdroid/osmdroid GitHub 新建项目 osmdroid在线&#xff1a; &#xff08;1&#xff09…...

一文上手skywalking【上】

一、skywalking预览 1.1 skywalking 概述 ​ Apache SkyWalking, 适用于分布式系统的应用程序性能监控工具&#xff0c;专为微服务、云原生和基于容器的 &#xff08;Kubernetes&#xff09; 架构而设计。官方地址: https://skywalking.apache.org/ 适用于分布式系统的应用程…...

【JavaScript】JQuery基础知识及应用

一、JQuery的导入方法 https://editor.csdn.net/md/?articleId132214798 二、JQuery介绍 JQuery(JQ)&#xff1a;JS的一个类库&#xff08;方法库&#xff1a;包含了大量的、有助于项目开发的属性和方法&#xff09; 第一代版本1.xx.xx: 1.11.3 兼容所有浏览器的&#xff0…...

初始爬虫9

1.元素定位后的操作 “find_element“仅仅能够获取元素&#xff0c;不能够直接获取其中的数据&#xff0c;如果需要获取数据需要使用以下方法”。下面列出了两个方法&#xff1a; 获取文本 element.text 通过定位获取的标签对象的 text 属性&#xff0c;获取文本内容 获取属性…...

从细胞到临床:表观组学分析技术在精准医疗中的角色

中国科学院等科研院所的顶尖人才发起&#xff0c;专注于多组学、互作组、生物医学等领域的研究与服务。在Nature等国际知名期刊发表多篇论文&#xff0c;提供实验整体打包、免费SCI论文润色等四大优势服务。在表观组学分析技术方面&#xff0c;提供DAP-seq、ATAC-seq、H3K4me3 …...

带你0到1之QT编程:二十、QT与MySQL喜结连理,构建数据库应用开发

此为QT编程的第二十谈&#xff01;关注我&#xff0c;带你快速学习QT编程的学习路线&#xff01; 每一篇的技术点都是很很重要&#xff01;很重要&#xff01;很重要&#xff01;但不冗余&#xff01; 我们通常采取总-分-总和生活化的讲解方式来阐述一个知识点&#xff01; …...

梯度下降法及其性能评估

梯度下降法 梯度下降法是一种一阶迭代优化算法&#xff0c;用于寻找函数的局部最小值。在机器学习中&#xff0c;它通常用来最小化损失函数&#xff08;也称为成本函数或误差函数&#xff09;&#xff0c;以提高模型对数据的拟合程度。梯度下降法的基本思想是沿着目标函数当前…...

906. 超级回文数

1. 题目 906. 超级回文数 2. 解题思路 题目意思很简单&#xff0c;在给定范围中找到所有满足&#xff0c;它本身是回文&#xff0c;且它的平方也是回文的数字个数。 这题需要注意题目给定的范围&#xff0c;后面很有用&#xff1a; 因为回文范围是有限的&#xff0c;那么我…...

代码随想录算法训练营||二叉树

前/中/后序遍历 递归方式 参考文章 题目 思路&#xff1a;其实递归方式的前中后序遍历的方式都差不多&#xff0c;区别是在父节点的遍历时间。 前序代码 class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> result new…...

线上报名小程序怎么做

在这个数字化、智能化的时代&#xff0c;信息技术的发展正以前所未有的速度改变着我们的生活。无论是学习、工作还是娱乐&#xff0c;互联网都成为了我们不可或缺的一部分。而在线上报名这一领域&#xff0c;小程序的出现更是为广大用户带来了前所未有的便捷与高效。今天&#…...

【测试岗】手撕代码 - 零钱兑换

322. 零钱兑换 题目描述 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1 。 你可以认为每种…...

菱形继承的类对父类的初始化、组合、多态、多态的原理等的介绍

文章目录 前言一、菱形继承的类对父类的初始化二、组合三、 多态1. 构成多态2. 虚函数3. 虚函数的重写4. 虚函数重写的两个例外1. 协变2. 析构函数的重写 5. C11 final 和 override1. final2. override 6. 设计不想被继承的类7. 重载、覆盖&#xff08;重写&#xff09;、 隐藏…...

React Native 在 build 的时候如果出现 `babel.config.js` 配置文件的错误

React Native 在 build 的时候如果出现以下错误, 就是 babel.config.js 配置文件的错误. Showing Recent Issues node:internal/process/promises:289triggerUncaughtException(err, true /* fromPromise */);^Error: .plugins[0][1] must be an object, false, or undefineda…...

【Linux】包管理器、vim详解及简单配置

&#x1f680;个人主页&#xff1a;小羊 &#x1f680;所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 前言一、包管理器1.1 apt1.2 yum 二、Linux编辑器——vim2.1 vim的三种模式2.2 vim普通模式常用命令2.2.1 移动…...

AVL树实现

1.AVL的概念 1.AVL树属于二叉搜索树的一种&#xff0c;但它不同与普通的二叉搜索树还具有以下的性质&#xff1a; 每一个根的左右子树的高度差的绝对值不超过1。AVL树是通过高度差去控制平衡的&#xff0c;所以又称作为平衡二叉搜索树。 2.AVL树实现我们引入了一个平衡因子的概…...

初始MYSQL数据库(6)—— 事务

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; MYSQL 目录 事务的概念 事务的ACID特性 使用事务 查看支持事务的存储引擎 事务的语法 保存点 自动/手动提交事务 事务的隔离性和…...

0基础学习PyTorch——GPU上训练和推理

大纲 创建设备训练推理总结 在《Windows Subsystem for Linux——支持cuda能力》一文中&#xff0c;我们让开发环境支持cuda能力。现在我们要基于《0基础学习PyTorch——时尚分类&#xff08;Fashion MNIST&#xff09;训练和推理》&#xff0c;将代码修改成支持cuda的训练和推…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

STM32F1 本教程使用零知标准板&#xff08;STM32F103RBT6&#xff09;通过I2C驱动ICM20948九轴传感器&#xff0c;实现姿态解算&#xff0c;并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化&#xff0c;适合嵌入式及物联网开发者。在基础驱动上新增…...