前端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中实现很多有趣和灵活的编程技巧,比如私有变量、模块化等。
通过使用闭包,我们可以创建更加灵活和复用的函数,同时能够保护一些内部状态不被外部轻易篡改。但需要小心使用闭包,因为过度或不正确地使用闭包可能导致内存泄漏或意外的变量共享问题。

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

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

相关文章

【维生素C语言】附录:strlen 函数详解

写在前面&#xff1a;本篇将专门为 strlen 函数进行讲解&#xff0c;总结了模拟实现 strlen 函数的三种方法&#xff0c;并对其进行详细的解析。手写库函数是较为常见的面试题&#xff0c;希望通过本篇博客能够加深大家对 strlen 的理解。 0x00 strlen函数介绍 【百度百科】str…

Cobalt Strike 的使用及拓展

Cobalt Strike是一款以Metasploit为基础的GUI框架式渗透测试工具&#xff0c;集成了端 口转发、服务扫描、 自动化溢出、多模式端口监听、exe 、PowerShell木马生成 等&#xff0c;主要用于团队作战&#xff0c;能让多个渗透者同时连接到团体服务器上&#xff0c;共享渗透资 源…

Leetcode2560. 打家劫舍 IV

Every day a Leetcode 题目来源&#xff1a;2560. 打家劫舍 IV 解法1&#xff1a;二分答案 动态规划 给定数组 nums&#xff0c;从中选择一个长度至少为 k 的子序列 A&#xff0c;要求 A 中没有任何元素在 nums 中是相邻的。 最小化 max⁡(A)。 看到「最大化最小值」或者…

基于vue+node.js的校园跳蚤市场系统多商家

校园跳蚤市场系统可以在短时间内完成大量的数据处理、帮助用户快速的查找校园跳蚤市场相关信息&#xff0c;实现的效益更加直观。校园跳蚤市场系统中采用nodejs技术和mysql数据库。主要包括管理员、发布者和用户三大部分&#xff0c;主要功能是实现对个人中心、用户管理、发布者…

数据分析基础之《pandas(7)—高级处理2》

四、合并 如果数据由多张表组成&#xff0c;那么有时候需要将不同的内容合并在一起分析 1、先回忆下numpy中如何合并 水平拼接 np.hstack() 竖直拼接 np.vstack() 两个都能实现 np.concatenate((a, b), axis) 2、pd.concat([data1, data2], axis1) 按照行或者列…

【Opencv学习】04-图像加法

文章目录 前言一、图像加法混合1.1 代码1.2 运行结果 二、图像的按位运算-组合相加2.1 代码2.2 运行结果示例&#xff1a;PPT平滑切换运行结果 总结 前言 简单说就是介绍了两张图如何组合在一起。 1、混合&#xff0c;透明度和颜色会发生改变 2、组合&#xff0c;叠加起来。可…

大厂的供应链域数据中台设计

关注我&#xff0c;紧跟本系列专栏文章&#xff0c;咱们下篇再续&#xff01; 作者简介&#xff1a;魔都技术专家兼架构&#xff0c;多家大厂后端一线研发经验&#xff0c;各大技术社区头部专家博主&#xff0c;编程严选网创始人。具有丰富的引领团队经验&#xff0c;深厚业务架…

2/10 BFS初探

其实在我看来解决全排列问题&#xff0c;核心还是顺序&#xff0c;想清楚结束条件&#xff0c;然后输出&#xff0c;以n3为例 #include<iostream> using namespace std; const int N 10; int path[N];//保存序列 int state[N];//数字是否被用过 int n; void dfs(int u) …

FPGA_工程_基于rom的vga显示

一 框图 二 代码修改 module Display #(parameter H_DISP 1280,parameter V_DISP 1024,parameter H_lcd 12d150,parameter V_lcd 12d150,parameter LCD_SIZE 15d10_000 ) ( input wire clk, input wire rst_n, input wire [11:0] lcd_xpos, //lcd horizontal coo…

C++面向对象 Part 2

文章目录 类六个默认存在的成员函数构造函数&#xff1a;析构函数&#xff1a;拷贝构造函数:拷贝构造详解及细节&#xff1a; 赋值运算符重载;取地址及const取地址操作符重载const修饰的含义&#xff1a; 类六个默认存在的成员函数 构造函数 析构函数 拷贝构造函数 赋值运算…

【从Python基础到深度学习】3. Winscp与Ubuntu使用及配置

一、Ubuntu的使用 1.1 开启与关闭 1.2 修改Ubuntu分辨率 选择适合自己电脑大小的分辨率 1.3 Ubuntu终端 1.4 网络测试 终端中输入&#xff1a; ping www.baidu.com ctr C 退出ping命令 1.5 下载软件 连通安装源 sudo apt update 安装 ssh vim sudo apt install ss…

Verilog刷题笔记22

题目&#xff1a; Build a priority encoder for 8-bit inputs. Given an 8-bit vector, the output should report the first (least significant) bit in the vector that is 1. Report zero if the input vector has no bits that are high. For example, the input 8’b100…

使用耳机壳UV树脂制作一个耳机壳需要多长时间?

使用耳机壳UV树脂制作一个耳机壳所需的时间取决于多个因素&#xff0c;包括工艺流程、加工方式、设备和技术水平等。一般来说&#xff0c;制作一个耳机壳需要数小时到数天不等。 以下是影响制作时间的几个主要因素&#xff1a; 获取耳模时间&#xff1a;获取耳模的时间取决于…

爬虫2—用爬虫爬取壁纸(想爬多少张爬多少张)

先看效果图&#xff1a; 我这个是爬了三页的壁纸60张。 上代码了。 import requests import re import os from bs4 import BeautifulSoupcount0 img_path "./壁纸图片/"#指定保存地址 if not os.path.exists(img_path):os.mkdir(img_path) headers{ "User-Ag…

第66讲管理员登录功能实现

项目样式初始化 放assets目录下&#xff1b; border.css charset "utf-8"; .border, .border-top, .border-right, .border-bottom, .border-left, .border-topbottom, .border-rightleft, .border-topleft, .border-rightbottom, .border-topright, .border-botto…

【Dubbo源码二:Dubbo服务导出】

入口 Dubbo服务导出的入口&#xff1a;服务导出是在DubboBootstrapApplicationListener在监听到ApplicationContextEvent的ContextRefreshedEvent事件后&#xff0c;会触发dubboBootstrap.start(), 在这个方法中最后会导出Dubbo服务 DubboBootstrapApplicationListener Dub…

Java异常处理 throw和throws

目录 throwthrows实例制造异常 在Java中&#xff0c;throw和throws关键字都与异常处理有关&#xff0c;但它们的使用方式和目的有所不同。 throw throw关键字&#xff1a; * throw用于在代码中显式地抛出一个异常。你可以使用它来触发一个异常&#xff0c;并指定异常的类型。…

python接口自动化---接口测试报告模板(详解)

简介 接口测试报告是软件测试过程中非常重要的一部分&#xff0c;通过接口测试报告我们可以了解系统在接口层面上的稳定性和可靠性。下面是一个简单的接口测试报告模板&#xff1a; 测试概述 在这个部分中&#xff0c;您需要简要阐述接口测试的目的和范围。测试环境 在这个部…

网络的基本概念和socket编程

网络的基本概念 1.协议1.1 协议的基本概念1.2 常见的协议 2.分层模型2.1网络七层OSI 7层模型&#xff1a;物数网传会表应(口诀)2.2TCP/IP模型2.3数据通信的过程2.4网络的设计模式2.5以太网帧的格式 3.SOCKET编程3.1网络字节序3.2 相关结构体和函数3.3 代码实现 1.协议 1.1 协议…

NAS如何成为生产力?使用绿联DX4600 Pro搭建图床并实现创作自由

NAS如何成为生产力&#xff1f;使用绿联DX4600 Pro搭建图床并实现创作自由 哈喽小伙伴们好&#xff0c;我是Stark-C~ 关注我的小伙伴都知道&#xff0c;我之前有分享过我的创作过程与工具&#xff0c;其中介绍了我个人其实一直都是使用Markdown的编辑器来进行图文创作的。 我…