前端JavaScript篇之对闭包的理解

目录

  • 对闭包的理解
    • 用途
    • 循环中使用闭包解决 var 定义函数的问题


对闭包的理解

闭包是指一个函数能够访问并操作其词法作用域(定义时所在的作用域)之外的变量的能力。它可以通过在一个函数内部创建另一个函数来实现。内部函数可以访问外部函数的局部变量、参数和其他内部函数,即使外部函数已经执行结束,这些变量仍然可以被内部函数引用。

用途

闭包的第一个用途是使我们在函数外部能够访问到函数内部的变量。通过使用闭包,可以通过在外部调用闭包函数,从而在外部访问到函数内部的变量。这种方法可以用来创建私有变量。

function outerFunction() {
  var privateVariable = 'I am a private variable'

  function innerFunction() {
    console.log(privateVariable) // 可以访问函数内部的变量
  }

  return innerFunction // 返回内部函数
}

var closure = outerFunction() // 创建闭包
closure() // 在外部访问函数内部变量,输出:I am a private variable

请添加图片描述

在上述代码中,我们定义了一个外部函数 outerFunction,它内部有一个私有变量 privateVariable。然后,我们在外部函数中定义了一个内部函数 innerFunction,内部函数可以访问和使用外部函数中的私有变量。最后,我们返回内部函数,并将其赋值给变量 closure。当我们调用 closure() 时,内部函数被执行,并输出了 privateVariable 的值。

闭包的第二个用途是使已经运行结束的函数上下文中的变量对象继续留在内存中。因为闭包函数保留了这个变量对象的引用,所以这个变量对象不会被回收。

function outerFunction() {
  var outerVariable = 'I am from outer function'

  function innerFunction() {
    console.log(outerVariable) // 访问已经运行结束的函数的变量
  }

  return innerFunction // 返回内部函数
}

var closure = outerFunction() // 创建闭包
closure() // 在外部访问已经运行结束的函数的变量,输出:I am from outer function

请添加图片描述

在上述代码中,我们定义了一个外部函数 outerFunction,它内部有一个变量 outerVariable。然后,我们在外部函数中定义了一个内部函数 innerFunction,内部函数可以访问和使用已经运行结束的函数的变量。最后,我们返回内部函数,并将其赋值给变量 closure。当我们调用 closure() 时,内部函数被执行,并输出了 outerVariable 的值。

综上所述,闭包的用途包括保护变量、记住状态、实现模块化、函数柯里化以及延迟执行和回调。通过合理地运用闭包,我们可以写出更加灵活、模块化和易于维护的JavaScript代码。

循环中使用闭包解决 var 定义函数的问题

当在循环中使用 var 关键字定义函数时,常常会遇到闭包问题。具体而言,闭包会共享同一个循环变量,导致函数在运行时使用的变量值不符合预期。为了解决这个问题,可以使用闭包和不同的解决方法。

以下是解决该问题的三种常见方法的详细解释和示例代码。

方法一:使用函数作用域和闭包

使用函数作用域和闭包的方法来解决循环中使用 var 定义函数的问题。具体操作是将函数定义在单独的作用域内,以创建一个新的闭包环境,使每个函数拥有独立的变量。

for (var i = 0; i < 5; i++) {
  ;(function () {
    var index = i // 创建新的变量,并将循环变量的值赋给它
    setTimeout(function () {
      console.log(index)
    }, 1000 * index)
  })()
}

请添加图片描述

在上述代码中,我们将匿名函数 (function() { ... })() 用于创建新的作用域。在这个作用域中,我们创建了一个新的变量 index,并将循环变量 i 的值赋给它。每次循环迭代都会创建一个独立的 index 变量,以避免共享循环变量导致的问题。

在闭包函数内部,我们使用 setTimeout 函数设置一个定时器,在延迟时间之后打印当前的 index 值。通过给定的延迟时间 1000 * index,我们可以按顺序输出 04 的值。

方法二:使用立即执行函数表达式和闭包

使用立即执行函数表达式(IIFE)和闭包来解决循环中使用 var 定义函数的问题。每次循环迭代时,都会创建一个新的闭包作用域,确保每个闭包函数拥有独立的变量。

for (var i = 0; i < 5; i++) {
  ;(function (index) {
    setTimeout(function () {
      console.log(index)
    }, 1000 * index)
  })(i)
}

在上述代码中,我们定义了一个立即执行的匿名函数 (function(index) { ... })(i),并将循环变量 i 作为参数传递给该函数。通过这种方式,在每次循环迭代中,都会创建一个新的闭包作用域,并将 index 参数的值绑定到闭包内部。因此,每个闭包函数都引用着自己独立的 index 变量,避免了共享循环变量的问题。

在闭包函数内部,我们使用 setTimeout 函数设置一个定时器,在延迟时间之后打印当前的 index 值。通过给定的延迟时间 1000 * index,我们可以按顺序输出 04 的值。

方法三:使用 let 关键字声明循环变量
使用 let 关键字来声明循环变量。let 声明的变量具有块级作用域,在每次循环迭代时都会创建一个新的变量实例,从而避免了变量共享的问题。

以下是使用 let 声明循环变量解决循环中使用 var 定义函数的问题的示例代码:

for (let i = 0; i < 5; i++) {
  setTimeout(function () {
    console.log(i)
  }, 1000 * i)
}

在上述代码中,我们使用 let 关键字来声明循环变量 i。由于每次循环迭代都会创建一个新的块级作用域,每个定时器回调函数都能够访问到自己独立的 i 变量,而不会受到外部循环的影响。

这三种方法都可以解决循环中使用 var 定义函数时的闭包问题。具体使用哪种方法取决于个人偏好和代码的情况。方法一适用于需要在闭包内部使用变量的复杂情况,而方法二和方法三更简洁明了,适用于简单的循环。

持续学习总结记录中,回顾一下上面的内容:
闭包是指函数可以访问其外部函数作用域中的变量,并且可以在其生命周期内保持对这些变量的引用。换句话说,闭包允许函数访问定义在自己外部的作用域中的变量,即使这些变量在外部函数执行完毕后仍然可以被访问和操作。
通俗地说,闭包就像是一个记忆力很好的函数,它可以记住并访问在它诞生时的环境中的东西。这意味着即使外部函数已经执行完毕,闭包仍然可以使用外部函数中的变量值。这种特性使得我们可以在JavaScript中实现很多有趣和灵活的编程技巧,比如私有变量、模块化等。
通过使用闭包,我们可以创建更加灵活和复用的函数,同时能够保护一些内部状态不被外部轻易篡改。但需要小心使用闭包,因为过度或不正确地使用闭包可能导致内存泄漏或意外的变量共享问题。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

6.0 Zookeeper session 基本原理详解教程

客户端与服务端之间的连接是基于 TCP 长连接&#xff0c;client 端连接 server 端默认的 2181 端口&#xff0c;也就 是 session 会话。 从第一次连接建立开始&#xff0c;客户端开始会话的生命周期&#xff0c;客户端向服务端的ping包请求&#xff0c;每个会话都可以设置一个…

HTML5+CSS3+移动web——HTML 基础

目录 一、标签语法 HTML的基本框架 1. 标题标签 2. 段落标签 3. 换行和水平线 4. 文本格式化标签 5. 图像标签 6. 路径 相对路径 绝对路径 7. 超链接标签 8. 音频 9. 视频 10. 注释 二、标签结构 一、标签语法 HTML 超文本标记语言——HyperText Markup Langua…

《动手学深度学习(PyTorch版)》笔记8.3

注&#xff1a;书中对代码的讲解并不详细&#xff0c;本文对很多细节做了详细注释。另外&#xff0c;书上的源代码是在Jupyter Notebook上运行的&#xff0c;较为分散&#xff0c;本文将代码集中起来&#xff0c;并加以完善&#xff0c;全部用vscode在python 3.9.18下测试通过&…

计算机网络——07协议层次及服务模型

协议层次及服务模型 协议层次 网络是一个复杂的系统 网络功能复杂&#xff1a;数字信号的物理信号承载、点到点、路由、rdt、进程区分、应用等现实来看&#xff0c;网络的许多构成元素和设备&#xff1a; 主机路由器各种媒体的链路应用协议硬件&#xff0c;软件 问题是&am…

单片机学习路线(简单介绍)

学习单片机对于电子爱好者和未来的嵌入式系统工程师来说是一段激动人心的旅程。单片机因其强大的功能、灵活性以及在各种智能设备中的广泛应用&#xff0c;成为了电子和计算机科学领域一个不可或缺的组成部分。如果你对如何开始这段旅程感到好奇&#xff0c;那么你来对地方了。…

Sqlite3安装步骤

1、Sqlite3以下载文件&#xff0c;配置环境变量的方式进行安装。 2、下方链接为官方的下载地址。 sqlite下载地址 2.1、需要两个下载文件&#xff0c;解压后将他们放在一起&#xff0c;假设解压后的路径为E:\sqlite。 sqlite-dll-win-x64-3450100.zip sqlite-tools-win-x6…

什么是CDR数字音频广播

一、什么是数字音频广播 CDR(China DigilalRadio)&#xff0c;即中国数字音领广播&#xff0c;是运用广播数字化技术&#xff0c;通过对音领信号进行信源编码、信道编码和载波调制传输&#xff0c;来实现数字音频广播业务和数据业务的播出。CDR与传统的FM调频广播相比&#xff…

【蓝桥杯冲冲冲】k 短路 / [SDOI2010] 魔法猪学院

蓝桥杯备赛 | 洛谷做题打卡day33 文章目录 蓝桥杯备赛 | 洛谷做题打卡day33题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 提示数据规模数据更新日志 题解代码我的一些话 【模板】k 短路 / [SDOI2010] 魔法猪学院 题目背景 注&#xff1a;对于 k k k 短路问…

第9章 智能租房——详情页

学习目标 掌握详情页房源数据展示功能的逻辑&#xff0c;能够实现在详情页上展示基本信息和配套设施 了解数据可视化&#xff0c;能够说出数据可视化的概念和流程 熟悉ECharts的用法和配置项&#xff0c;能够通过ECharts绘制常用图表&#xff0c;并为图表添加配置项 掌握户型…

2024年 前端JavaScript入门到精通 第一天

主要讲解JavaScript核心知识&#xff0c;包含最新ES6语法&#xff0c;从基础到API再到高级。让你一边学习一边练习&#xff0c;重点知识及时实践&#xff0c;同时每天安排大量作业&#xff0c;加深记忆&#xff0c;巩固学习成果。 1.1 基本软件与准备工作 1.2 JavaScript 案例 …

前端开发_AJAX基本使用

AJAX概念 AJAX是异步的JavaScript和XML(Asynchronous JavaScript And XML)。 简单点说&#xff0c;就是使用XMLHttpRequest对象与服务器通信。 它可以使用JSON&#xff0c;XML&#xff0c;HTML和text文本等格式发送和接收数据。 AJAX最吸引人的就是它的“异步"特性&am…

python-分享篇-GUI界面开发-PyQt5-对QListWidget表格进行数据绑定

代码 # -*- coding: utf-8 -*-# Form implementation generated from reading ui file bindtable.ui # # Created by: PyQt5 UI code generator 5.11.3 # # WARNING! All changes made in this file will be lost! 对QTableWidget表格进行数据绑定from PyQt5 import QtCore, Q…

Wireshark不显示Thrift协议

使用Wireshark对thrift协议进行抓包&#xff0c;但是只显示了传输层的tcp协议&#xff1a; "右键" -> "Decode As" 选择thrift的tcp端口 将“当前”修改为Thrift&#xff0c;然后点击“确定” 设置后&#xff0c;可以发现Wireshark里面显示的协议从Tcp变…

正版软件 - Proxyman:让网络调试变得更智能、更高效

在软件开发的世界里&#xff0c;网络调试一直是开发者和测试工程师的痛点。传统的调试工具往往操作复杂&#xff0c;界面不够直观&#xff0c;而且性能上也难以满足现代应用的需求。今天&#xff0c;我要向大家介绍一款名为Proxyman的网络调试工具&#xff0c;它以其简洁的界面…

第十八篇【传奇开心果短博文系列】Python的OpenCV库技术点案例示例:图像修复和恢复

传奇开心果短博文系列 系列短博文目录Python的OpenCV库技术点案例示例系列短博文目录前言一、常用的图像修复与恢复技术二、插值方法示例代码三、基于纹理合成的方法示例代码四、基于边缘保持的方法示例代码五、基于图像修复模型的方法示例代码六、基于深度学习的方法示例代码七…

Vulnhub靶机:hacksudo-search

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.15&#xff09; 靶机&#xff1a;hacksudo-search&#xff08;10.0.2.50&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://download.vulnhub.co…

【leetcode热题100】 格雷编码

n 位格雷码序列 是一个由 2n 个整数组成的序列&#xff0c;其中&#xff1a; 每个整数都在范围 [0, 2n - 1] 内&#xff08;含 0 和 2n - 1&#xff09;第一个整数是 0一个整数在序列中出现 不超过一次每对 相邻 整数的二进制表示 恰好一位不同 &#xff0c;且第一个 和 最后一…

c语言游戏实战(4):人生重开模拟器

前言&#xff1a; 人生重开模拟器是前段时间非常火的一个小游戏&#xff0c;接下来我们将一起学习使用c语言写一个简易版的人生重开模拟器。 网页版游戏&#xff1a; 人生重开模拟器 (ytecn.com) 1.实现一个简化版的人生重开模拟器 &#xff08;1&#xff09; 游戏开始的时…

Python算法题集_随机链表的复制

Python算法题集_随机链表的复制 题138&#xff1a;随机链表的复制1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【双层循环】2) 改进版一【字典哈希】3) 改进版二【单层哈希】4) 改进版三【递归大法】 4. 最优算法 本文为Python算法题集之一的…

Python 错误及其解决方法

Python 是一种易于学习的编程语言&#xff0c;但初学者在学习和使用 Python 的过程中难免会遇到一些错误。以下是一些常见的 Python 错误及其解决方法&#xff1a; 1. 语法错误&#xff08;SyntaxError&#xff09;&#xff1a; python # 错误示例 print("Hello, World!…