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

六十天前端强化训练之第十二天之闭包深度解析

=====欢迎来到编程星辰海的博客讲解======

目录

第一章:闭包的底层运行机制

1.1 词法环境(Lexical Environment)的构成JavaScript 引擎通过三个关键组件管理作用域:

1.2 作用域链的创建过程当函数被定义时:

1.3 闭包变量的生命周期

第二章:内存管理深度剖析

2.1 内存泄漏的典型场景

2.2 V8引擎的优化策略

第三章:高级应用场景

3.1 模块模式实现

3.2 缓存优化实践

3.3 函数工厂模式

第四章:性能优化关键

4.1 避免闭包滥用准则

4.2 内存释放最佳实践

4.3 现代浏览器优化特性

第五章:经典案例分析

5.1 循环陷阱与解决方案问题代码:

5.2 封装私有状态

第六章:多语言对比

6.1 Python闭包实现

6.2 Java伪闭包实现

第七章:调试与诊断

7.1 Chrome DevTools 实战

7.2 Node.js 内存分析

第八章:前沿技术演进

8.1 WebAssembly 中的闭包处理

8.2 函数式编程的闭包应用

第九章:安全相关考量

9.1 信息隐藏风险

9.2 防御性编程实践

第十章:综合应用案例

10.1 实现状态管理库

终极知识图谱


第一章:闭包的底层运行机制

1.1 词法环境(Lexical Environment)的构成
JavaScript 引擎通过三个关键组件管理作用域:
  • 环境记录(Environment Record):存储变量和函数声明的实际位置
  • 对外部词法环境的引用(Outer Reference):构成作用域链的核心链路
  • 状态标记(Status Flags):记录环境是否处于可访问状态

典型闭包环境结构:

JAVASCRIPT

function factory(name) {let privateVar = 100; // 进入环境记录return {get: () => privateVar,set: (v) => privateVar = v};
}
1.2 作用域链的创建过程
当函数被定义时:
  1. 引擎创建函数对象的 [[Environment]] 隐藏属性
  2. 属性值 = 当前执行上下文的词法环境
  3. 调用时使用 [[Environment]] 创建新的词法环境
1.3 闭包变量的生命周期
  • 普通变量:函数执行完毕即销毁
  • 闭包变量:至少存在一个函数引用该变量 → 变量被保留
  • 释放条件:所有引用该环境的函数对象都被销毁

第二章:内存管理深度剖析

2.1 内存泄漏的典型场景

JAVASCRIPT

// 意外全局引用
function leaky() {const bigData = new Array(1e6).fill('*');return function() {console.log(bigData[0]); // 保持对bigData的引用};
}// 循环引用陷阱
function createCircularRef() {const obj = { data: 'secret' };obj.self = obj; // 自引用return () => obj;
}
2.2 V8引擎的优化策略
  • 隐藏类(Hidden Class):优化对象访问
  • 内联缓存(Inline Caching):加速属性查找
  • 分代垃圾回收:Young Generation / Old Generation

2.3 诊断工具使用
Chrome Memory 面板操作:

  1. 拍摄堆快照(Heap Snapshot)
  2. 搜索闭包函数名
  3. 查看 Retained Size 分析内存占用

第三章:高级应用场景

3.1 模块模式实现

JAVASCRIPT

const calculator = (() => {let precision = 2;const format = num => num.toFixed(precision);return {add: (a, b) => format(a + b),setPrecision: (p) => precision = p};
})();console.log(calculator.add(0.1, 0.2)); // "0.30"
calculator.setPrecision(4);
console.log(calculator.add(1.234, 2.345)); // "3.5790"
3.2 缓存优化实践

JAVASCRIPT

function createCache(fn) {const cache = new Map();return function(param) {if (cache.has(param)) {console.log('Cache hit');return cache.get(param);}const result = fn(param);cache.set(param, result);return result;};
}const heavyCompute = n => { /* 复杂计算 */ };
const cachedCompute = createCache(heavyCompute);
3.3 函数工厂模式

JAVASCRIPT

function createValidator(rules) {const validators = [];for (const [field, validateFn] of Object.entries(rules)) {validators.push(value => {try {return validateFn(value);} catch (e) {throw new Error(`${field} validation failed: ${e.message}`);}});}return function(data) {return validators.every(validator => validator(data));};
}const validateUser = createValidator({age: v => v >= 18,email: v => /.+@.+\..+/.test(v)
});

第四章:性能优化关键

4.1 避免闭包滥用准则
  • 层级嵌套不超过3层
  • 单个闭包捕获变量数 < 10个
  • 高频调用函数避免闭包
4.2 内存释放最佳实践

JAVASCRIPT

// 显式解除引用
function createResource() {const resource = allocateLargeResource();const handlers = [];const cleanUp = () => {resource.release();handlers.length = 0; // 断开事件监听};return {addHandler: fn => handlers.push(fn),dispose: cleanUp};
}const res = createResource();
// 使用完毕后
res.dispose();
4.3 现代浏览器优化特性
  • Slimming Closure:Chromium 的闭包优化策略
  • Scavenge GC:快速回收短期闭包
  • Compilation Cache:字节码缓存复用

第五章:经典案例分析

5.1 循环陷阱与解决方案
问题代码:

JAVASCRIPT

for (var i = 0; i < 5; i++) {setTimeout(() => console.log(i), 100);
} // 输出5个5

三种修复方案:

JAVASCRIPT

// 方案1:使用IIFE创建作用域
for (var i = 0; i < 5; i++) {(function(j) {setTimeout(() => console.log(j), 100);})(i);
}// 方案2:使用let声明
for (let i = 0; i < 5; i++) {setTimeout(() => console.log(i), 100);
}// 方案3:利用第三个参数
for (var i = 0; i < 5; i++) {setTimeout(j => console.log(j), 100, i);
}
5.2 封装私有状态

JAVASCRIPT

class PrivateCounter {#count = 0; // ES2022私有字段increment() {this.#count++;}
}// 闭包实现等价功能
function closureCounter() {let count = 0;return {increment: () => ++count,get: () => count};
}

第六章:多语言对比

6.1 Python闭包实现

PYTHON

def outer():x = 10def inner():nonlocal xx += 1return xreturn innerf = outer()
print(f()) # 11
print(f()) # 12
6.2 Java伪闭包实现

JAVA

// 通过匿名类模拟
interface Counter {int increment();
}public class Test {public static Counter create() {final int[] count = {0}; // 使用数组绕过final限制return new Counter() {public int increment() {return ++count[0];}};}
}

第七章:调试与诊断

7.1 Chrome DevTools 实战
  1. 打开 Sources 面板
  2. 设置断点在闭包函数内
  3. 查看 Scope 面板的 Closure 项
  4. 使用 Memory 面板分析内存占用
7.2 Node.js 内存分析

BASH

# 生成堆快照
node --inspect-brk app.js
# 使用Chrome DevTools分析.heapsnapshot文件

第八章:前沿技术演进

8.1 WebAssembly 中的闭包处理
  • 通过 Table 类型管理函数引用
  • 严格的类型系统限制
  • 内存管理的显式控制
8.2 函数式编程的闭包应用

JAVASCRIPT

// 柯里化示例
const curry = fn => (...args) => args.length >= fn.length ? fn(...args) : curry(fn.bind(null, ...args));const add = curry((a, b, c) => a + b + c);
console.log(add(1)(2)(3)); // 6

第九章:安全相关考量

9.1 信息隐藏风险

JAVASCRIPT

const createWallet = () => {let balance = 0;return {topUp: amount => balance += amount,// 未提供余额查询接口 → 真正私有pay: amount => balance -= amount};
};
9.2 防御性编程实践

JAVASCRIPT

function safeClosure() {let sensitiveData = 'confidential';return Object.freeze({getData: () => {validatePermission();return sensitiveData;}});function validatePermission() {if (!checkAuth()) throw new Error('Access denied');}
}

第十章:综合应用案例

10.1 实现状态管理库

JAVASCRIPT

function createStore(reducer) {let state = reducer(undefined, {});const subscribers = new Set();return {getState: () => state,dispatch: action => {state = reducer(state, action);subscribers.forEach(fn => fn());},subscribe: fn => {subscribers.add(fn);return () => subscribers.delete(fn);}};
}// 使用示例
const store = createStore(counterReducer);
store.subscribe(() => console.log(store.getState()));
store.dispatch({ type: 'INCREMENT' });

终极知识图谱

通过以上体系化的解析,开发者可以全面掌握闭包的核心原理与实践技巧。建议结合具体项目需求,在以下场景优先考虑使用闭包:

  • 需要持久化局部状态的工具函数
  • 实现带有私有变量的业务模块
  • 创建可配置的函数工厂
  • 需要延迟执行的回调管理

同时注意遵循以下开发准则:

  1. 最小化捕获变量原则
  2. 显式资源释放机制
  3. 避免多层嵌套的闭包结构
  4. 定期进行内存泄漏检测

最后要记住:闭包不是银弹,理解其双刃剑特性,在合适场景发挥其独特优势,才是高级开发者的正确使用姿势。

相关文章:

六十天前端强化训练之第十二天之闭包深度解析

欢迎来到编程星辰海的博客讲解 目录 第一章&#xff1a;闭包的底层运行机制 1.1 词法环境&#xff08;Lexical Environment&#xff09;的构成JavaScript 引擎通过三个关键组件管理作用域&#xff1a; 1.2 作用域链的创建过程当函数被定义时&#xff1a; 1.3 闭包变量的生命…...

DeepSeek R1-32B医疗大模型的完整微调实战分析(全码版)

DeepSeek R1-32B微调实战指南 ├── 1. 环境准备 │ ├── 1.1 硬件配置 │ │ ├─ 全参数微调:4*A100 80GB │ │ └─ LoRA微调:单卡24GB │ ├── 1.2 软件依赖 │ │ ├─ PyTorch 2.1.2+CUDA │ │ └─ Unsloth/ColossalAI │ └── 1.3 模…...

10.2 继承与多态

文章目录 继承多态 继承 继承的作用是代码复用。派生类自动获得基类的除私有成员外的一切。基类描述一般特性&#xff0c;派生类提供更丰富的属性和行为。在构造派生类时&#xff0c;其基类构造函数先被调用&#xff0c;然后是派生类构造函数。在析构时顺序刚好相反。 // 基类…...

[网络爬虫] 动态网页抓取 — Selenium 元素定位

&#x1f31f;想系统化学习爬虫技术&#xff1f;看看这个&#xff1a;[数据抓取] Python 网络爬虫 - 学习手册-CSDN博客 在使用 Selenium 时&#xff0c;往往需要先定位到指定元素&#xff0c;然后再执行相应的操作。例如&#xff0c;再向文本输入框中输入文字之前&#xff0c;…...

静态网页的爬虫(以电影天堂为例)

一、电影天堂的网址&#xff08;url&#xff09; 电影天堂_免费电影_迅雷电影下载_电影天堂网最好的迅雷电影下载网&#xff0c;分享最新电影&#xff0c;高清电影、综艺、动漫、电视剧等下载&#xff01;https://dydytt.net/index.htm 我们要爬取这个页面上的内容 二、代码…...

将图片存储至阿里云 OSS

将图片存储至阿里云 OSS 一、概述 在项目开发中&#xff0c;我们常常需要处理用户上传的图片。本文将介绍如何使用前端的 el-upload 组件将照片上传到后端&#xff0c;后端再将照片存储到阿里云 OSS&#xff0c;并最终返回图片的 URL 给前端。 二、前端实现 1. 安装依赖 确…...

Android设备是如何进入休眠的呢?

首先我们手机灭屏后&#xff0c;一般需要等一段时间CPU才真正进入休眠。即Android设备屏幕暗下来的时候&#xff0c;并不是立即就进入了休眠模式&#xff1b;当所有唤醒源都处于de-avtive状态后&#xff0c;系统才会进入休眠。在手机功耗中从灭屏开始到CPU进入休眠时间越短&…...

ctfshow做题笔记—栈溢出—pwn65~pwn68

目录 前言 一、pwn65(你是一个好人) 二、pwn66(简单的shellcode&#xff1f;不对劲&#xff0c;十分得有十二分的不对劲) 三、pwn67(32bit nop sled)&#xff08;确实不会&#xff09; 四、pwn68(64bit nop sled) 前言 做起来比较吃力哈哈&#xff0c;自己还是太菜了&…...

高效处理 List<T> 集合:更新、查找与优化技巧

引言 在日常开发中,List<T> 是我们最常用的数据结构之一。无论是批量更新数据、查找特定项还是进行复杂的集合操作,掌握 List<T> 的高级用法可以显著提高代码的效率和可读性。本文将详细介绍如何使用 List<T> 进行批量更新、查找匹配项以及优化性能的方法…...

Java基础系列:深入解析final与static关键字的奥秘与避坑指南

目录 一、final关键字的四重境界 1. 修饰常量&#xff08;成员变量/局部变量&#xff09; 2. 修饰方法&#xff08;禁止重写&#xff09; 3. 修饰类&#xff08;禁止继承&#xff09; 4. 并发控制&#xff08;内存屏障&#xff09; 二、static关键字的四维空间 1. 静态变…...

django各种mixin用法

在 Django 中,Mixin 是一种用于扩展类功能的设计模式。通过 Mixin,可以在不修改原有类的情况下,为其添加新的方法或属性。Django 中的 Mixin 广泛应用于视图(View)、表单(Form)、模型(Model)等组件中。以下是 Django 中常见 Mixin 的用法和示例: 一、视图(View)中的…...

JS中的闭包(closures)一种强大但易混淆的概念

JavaScript 中的闭包&#xff08;closures&#xff09;被认为是一种既强大又易混淆的概念。闭包允许函数访问其外部作用域的变量&#xff0c;即使外部函数已执行完毕&#xff0c;这在状态维护和回调函数中非常有用。但其复杂性可能导致开发者的误解&#xff0c;尤其在变量捕获和…...

Element使用

Element(美化网页&#xff09; ElementUI的使用注意事项&#xff1a; Element.ui的使用基于Vue环境&#xff0c;于是Element相关组件的使用必须放在Vue对象绑定的视图中去 ElementUI的JS库的引入必须放在vue.js库的后面 <!-- 引入样式 --><link rel"styleshee…...

基于YOLO11深度学习的电瓶车进电梯检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…...

R语言的基础命令及实例操作

> T & F [1] FALSE > T & T [1] TRUE > T | F [1] TRUE > F | F [1] FALSE > a <- c(T,F,T) > b <- c(F,F,T) > a & b [1] FALSE FALSE TRUE > a | b [1] TRUE FALSE TRUE 在 R 中&#xff0c;大小写是敏感的&#xff0c;也就是说…...

AI视频生成工具清单(附网址与免费说明)

以下是一份详细的AI视频制作网站总结清单&#xff0c;包含免费/付费信息及核心功能说明&#xff1a; AI视频生成工具清单&#xff08;附网址与免费说明&#xff09; 1. Synthesia 网址&#xff1a;https://www.synthesia.io是否免费&#xff1a;免费试用&#xff08;生成视频…...

知识蒸馏综述Knowledge Distillation: A Survey解读

论文链接&#xff1a;Knowledge Distillation: A Survey 摘要&#xff1a;近年来&#xff0c;深度神经网络在工业界和学术界都取得了成功&#xff0c;尤其是在计算机视觉任务方面。深度学习的巨大成功主要归功于它能够扩展以对大规模数据进行编码&#xff0c;并且能够处理数十…...

第十五届蓝桥杯省赛电子类单片机学习过程记录(客观题)

客观试题: 01.典型的BUCK电源电路包含哪些关键器件(ABCD) A. 电容 B. 二极管 C. 电感 D. MOSFET 解析: 典型的 BUCK 电源电路是一种降压型的直流-直流转换电路,它包含以下关键器件: A.电容:电容在电路中起到滤波的作用。输入电容用于平滑输入电压的波动,减少电源噪声对…...

【C++】:STL详解 —— 红黑树封装map和set

目录 红黑树的源代码 正向迭代器的代码 反向迭代器的代码 set的模拟实现 map的模拟实现 红黑树的源代码 #pragma once #include <iostream>using namespace std; // set ->key // map ->key/value// set ->key // map ->key/valueenum Colour {RED,BLAC…...

【QWEN】机器人控制器的控制周期越短精度越高吗

好的&#xff0c;用户问的是“机器人控制器的控制周期越短精度越高吗”。我需要根据提供的知识库内容来回答这个问题。首先&#xff0c;我得回忆一下知识库里的相关信息。 知识库里有几篇相关的文章。比如&#xff0c;[3]提到控制周期越短&#xff0c;控制性能的上限越高&…...

使用数据库和缓存的时候,是如何解决数据不一致的问题的?

1.缓存更新策略 1.1. 缓存旁路模式&#xff08;Cache Aside&#xff09; 在应用里负责管理缓存&#xff0c;读取时先查缓存&#xff0c;如果命中了则返回缓存&#xff0c;如果未命中就查询数据库&#xff0c;然后返回缓存&#xff0c;返回缓存的同时把数据给写入缓存中。更新…...

【c++】平移字符串

说明 实现字符串的左移与右移 示例代码 #include <iostream> #include <string> using namespace std;int main() {string str1 "12345";//左移2位string str2 str1.substr(2) str1.substr(0, 2);cout << str2 << endl;//右移2位&…...

基于Spring Boot的多级缓存架构实现

基于Spring Boot的多级缓存架构实现 以下是一个基于Spring Boot的多级缓存架构实现示例 多级缓存架构实现方案 1. 依赖配置&#xff08;pom.xml&#xff09; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-star…...

为什么DDPG需要目标网络而A2C不需要?

在强化学习中&#xff0c;DDPG需要目标网络而A2C不需要的主要原因在于算法架构、更新方式和目标稳定性需求的差异&#xff1a; Q值估计的稳定性需求不同 DDPG的Critic网络需要估计状态-动作值函数 Q ( s , a ) Q(s,a) Q(s,a)&#xff0c;其目标值的计算涉及下一个状态的最大Q值…...

蓝桥杯 C++ b组 统计子矩阵深度解析

题目大意&#xff1a;给定一个 NM 的矩阵 A&#xff0c;请你统计有多少个子矩阵 (最小11&#xff0c;最大NM) 满足子矩阵中所有数的和不超过给定的整数 K&#xff1f; 前言&#xff1a;这题很容易想到二维前缀和优化&#xff0c;然后枚举子矩阵&#xff0c;但这样时间复杂度为…...

YOLOv12本地部署教程——42%速度提升,让高效目标检测触手可及

YOLOv12 是“你只看一次”&#xff08;You Only Look Once, YOLO&#xff09;系列的最新版本&#xff0c;于 2025 年 2 月发布。它引入了注意力机制&#xff0c;提升了检测精度&#xff0c;同时保持了高效的实时性能。在保持速度的同时&#xff0c;显著提升了检测精度。例如&am…...

每天五分钟深度学习PyTorch:向更深的卷积神经网络挑战的ResNet

本文重点 ResNet大名鼎鼎,它是由何恺明团队设计的,它获取了2015年ImageNet冠军,它很好的解决了当神经网络层数过多出现的难以训练的问题,它创造性的设计了跳跃连接的方式,使得卷积神经网络的层数出现了大幅度提升,设置可以达到上千层,可以说resnet对于网络模型的设计具…...

C++11新特性 11.基于范围的for循环

一.简介 基本概念&#xff1a; 在 C 中&#xff0c;基于范围的 for 循环&#xff08;Range-based for loop&#xff09;是一种简化容器遍历的语法糖&#xff0c;适用于所有支持 begin() 和 end() 的容器&#xff08;如 vector、map、array 等&#xff09;。以下是其核心用法和…...

Linux搜索---locate

locate locate 是 Linux 系统中用于快速查找文件和目录的命令。它并非实时遍历文件系统&#xff0c;而是通过搜索预先建立的文件数据库来定位文件。该数据库由 updatedb 程序定期&#xff08;通常是每天&#xff09;更新&#xff0c;收录了系统中所有文件的路径信息&#xff0…...

c语言笔记 一维数组与二维数组

1.一维数组和二维数组名加1代表什么意思&#xff0c;偏移多少单位&#xff1f; 方法&#xff1a;1就是以数组的元素类型的字节为单位去偏移。 先看结论再代码验证&#xff1a; 一维数组名&#xff0b;1表示加一个整型单位的偏移量&#xff0c;也可以这么理解1就是以数组的元…...