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

闭包的两种设计模式

闭包设计模式

概述

闭包是 JavaScript 中的一个重要概念,它允许内层函数访问外层函数的变量。在实际开发中,闭包经常被用于实现特定的设计模式,主要包括辅助函数模式工厂模式

1. 辅助函数模式(Helper Function Pattern)

基本结构

function mainFunction(params) {// 外层变量:状态存储let sharedState = initialValue;function helperFunction(helperParams) {// 内层函数:核心逻辑实现// 可以访问和修改 sharedState}// 调用辅助函数helperFunction(params);return sharedState;  // 返回处理结果
}

特点分析

  • 目的:代码组织和私有化
  • 生命周期:单次调用期间
  • 状态管理:临时状态,每次调用重新初始化
  • 访问权限:辅助函数无法被外部直接访问
  • 使用场景:递归算法、复杂逻辑分解

实际应用示例

1. 数组扁平化
function flatArr(list) {let result = [];function flat(currentList) {  // 私有辅助函数for (let i = 0; i < currentList.length; i++) {if (!Array.isArray(currentList[i])) {result.push(currentList[i]);} else {flat(currentList[i]);  // 递归调用}}}flat(list);return result;
}// 使用示例
console.log(flatArr([1, [2, 3], [4, [5, 6]]])); // [1, 2, 3, 4, 5, 6]
2. 深度优先搜索
function dfsCollect(tree) {let result = [];function dfs(node) {  // 私有辅助函数if (!node) return;result.push(node.value);if (node.children) {node.children.forEach(dfs);}}dfs(tree);return result;
}
3. 对象深拷贝
function deepClone(obj) {let visited = new WeakMap();  // 解决循环引用function clone(current) {  // 私有辅助函数if (current === null || typeof current !== 'object') {return current;}if (visited.has(current)) {return visited.get(current);}const result = Array.isArray(current) ? [] : {};visited.set(current, result);for (let key in current) {if (current.hasOwnProperty(key)) {result[key] = clone(current[key]);}}return result;}return clone(obj);
}

2. 工厂模式 + 装饰器模式(Factory + Decorator Pattern)

基本结构

function createEnhancedFunction(originalFunction) {// 外层变量:持久状态const persistentState = {};return function enhancedFunction(...args) {// 增强逻辑:使用持久状态提供额外功能// 调用原函数并返回结果return originalFunction(...args);};
}

特点分析

  • 目的:增强函数功能,状态管理
  • 生命周期:长期存在,跨多次调用
  • 状态管理:持久状态,每个实例独立维护
  • 访问权限:返回的函数可以被外部调用
  • 使用场景:缓存、节流、防抖、日志记录

实际应用示例

1. 函数缓存(记忆化)
function createCache(fn) {const cache = new Map();  // 持久缓存状态return function (...args) {  // 增强的函数const key = JSON.stringify(args);if (cache.has(key)) {console.log(`Cache hit for args: ${key}`);return cache.get(key);}console.log(`Cache miss for args: ${key}`);const result = fn(...args);cache.set(key, result);return result;};
}// 使用示例
const fibonacci = createCache(function(n) {if (n <= 1) return n;return fibonacci(n - 1) + fibonacci(n - 2);
});console.log(fibonacci(10)); // 计算并缓存
console.log(fibonacci(10)); // 从缓存获取
2. 函数节流
function createThrottle(delay) {let lastTime = 0;  // 持久时间状态return function(fn) {  // 增强的函数return function(...args) {const now = Date.now();if (now - lastTime >= delay) {lastTime = now;return fn.apply(this, args);}};};
}// 使用示例
const throttle = createThrottle(1000);
const throttledLog = throttle(console.log);
3. 函数调用计数器
function createCounter(fn) {let count = 0;  // 持久计数状态return function(...args) {  // 增强的函数count++;console.log(`函数被调用了 ${count}`);return fn.apply(this, args);};
}// 使用示例
const countedAdd = createCounter((a, b) => a + b);
console.log(countedAdd(1, 2)); // 函数被调用了 1 次 \n 3
console.log(countedAdd(3, 4)); // 函数被调用了 2 次 \n 7
4. 函数执行时间统计
function createTimer(fn) {const stats = { totalTime: 0, callCount: 0 };  // 持久统计状态return function(...args) {  // 增强的函数const start = Date.now();const result = fn.apply(this, args);const end = Date.now();stats.totalTime += (end - start);stats.callCount++;stats.averageTime = stats.totalTime / stats.callCount;console.log(`执行时间: ${end - start}ms, 平均时间: ${stats.averageTime}ms`);return result;};
}

3. 两种模式对比

特性辅助函数模式工厂模式 + 装饰器模式
主要目的代码组织和逻辑分解功能增强和状态管理
状态生命周期单次调用期间跨多次调用持久存在
状态初始化每次调用重新初始化创建时初始化,后续复用
函数可见性辅助函数私有返回增强后的公开函数
使用方式直接调用主函数先创建增强函数,再调用
典型应用递归算法、复杂计算缓存、节流、装饰器

4. 选择指南

使用辅助函数模式的场景:

  • 需要将复杂逻辑分解为多个步骤
  • 实现递归算法时需要维护中间状态
  • 希望隐藏实现细节,只暴露主要接口
  • 需要在单次执行中共享临时变量

使用工厂模式 + 装饰器模式的场景:

  • 需要为现有函数添加额外功能
  • 需要维护跨调用的持久状态
  • 实现缓存、节流、防抖等功能增强
  • 需要创建多个具有相似功能但独立状态的函数

5. 常见问题解答(FAQ)

Q: 多个 createCache 实例会造成缓存冲突吗?

A: 不会冲突。每次调用 createCache(fn) 都会创建一个全新的闭包环境,每个返回的函数都有自己独立的 cache 变量。

原理解释
function createCache(fn) {const cache = new Map();  // 每次调用createCache都会创建新的cachereturn function (...args) {// 这个返回的函数只能访问它所属闭包环境中的cacheconst key = JSON.stringify(args);if (cache.has(key)) {console.log(`Cache hit for ${fn.name}: ${key}`);return cache.get(key);}console.log(`Cache miss for ${fn.name}: ${key}`);const result = fn(...args);cache.set(key, result);return result;};
}
实际验证示例
// 创建两个不同的缓存函数
const cachedAdd = createCache(function add(a, b) {return a + b;
});const cachedMultiply = createCache(function multiply(a, b) {return a * b;
});// 测试:相同参数但不同函数
console.log('=== 第一次调用 ===');
console.log(cachedAdd(2, 3));      // Cache miss for add: [2,3] -> 5
console.log(cachedMultiply(2, 3));  // Cache miss for multiply: [2,3] -> 6console.log('=== 第二次调用相同参数 ===');
console.log(cachedAdd(2, 3));      // Cache hit for add: [2,3] -> 5
console.log(cachedMultiply(2, 3));  // Cache hit for multiply: [2,3] -> 6// 结果:每个函数都有自己独立的缓存,互不影响
闭包作用域独立性
// 每次调用 createCache 时的内存模型:
const fn1 = createCache(addFunction);    // 创建闭包环境1,有独立的cache1
const fn2 = createCache(multiplyFunction); // 创建闭包环境2,有独立的cache2// 内存结构示意:
/*
闭包环境1: {cache: Map { [2,3] => 5 }  // 独立的缓存空间1return function1
}闭包环境2: {cache: Map { [2,3] => 6 }  // 独立的缓存空间2return function2
}
*/// fn1 只能访问 cache1
// fn2 只能访问 cache2
// 它们完全独立,互不影响
需要注意的场景
// 同一个函数创建多个缓存实例
const fibonacci = function(n) {if (n <= 1) return n;return fibonacci(n - 1) + fibonacci(n - 2);
};const cache1 = createCache(fibonacci);
const cache2 = createCache(fibonacci);// 这样会创建两个独立的缓存,可能造成重复计算
console.log(cache1(10)); // 第一个缓存计算
console.log(cache2(10)); // 第二个缓存重新计算(因为缓存是独立的)
最佳实践
// 1. 单例模式:对于同一个函数,通常只创建一个缓存实例
const cachedFibonacci = createCache(function fibonacci(n) {if (n <= 1) return n;return cachedFibonacci(n - 1) + cachedFibonacci(n - 2);
});// 2. 带清理功能的缓存
function createCacheWithClear(fn) {const cache = new Map();const cachedFn = function (...args) {const key = JSON.stringify(args);if (cache.has(key)) {return cache.get(key);}const result = fn(...args);cache.set(key, result);return result;};// 添加清理方法cachedFn.clearCache = () => cache.clear();cachedFn.getCacheSize = () => cache.size;return cachedFn;
}// 使用示例
const smartCache = createCacheWithClear((x) => x * x);
console.log(smartCache(5)); // 25
console.log(smartCache.getCacheSize()); // 1
smartCache.clearCache();
console.log(smartCache.getCacheSize()); // 0

6. 最佳实践

性能考虑

  • 辅助函数模式:避免在频繁调用的函数中使用复杂的辅助逻辑
  • 工厂模式:注意内存泄漏,合理管理持久状态的生命周期

可读性优化

  • 使用描述性的函数名称
  • 添加适当的注释说明闭包的用途
  • 保持函数职责单一

调试技巧

  • 在开发环境中添加日志输出
  • 使用浏览器开发者工具的断点调试
  • 注意闭包可能导致的内存占用

总结

闭包设计模式是 JavaScript 中强大的编程工具,通过合理运用辅助函数模式和工厂模式,可以写出更加优雅、可维护的代码。关键是要根据具体的使用场景选择合适的模式,并注意性能和内存管理的最佳实践。

核心要点:

  • 每个闭包创建独立的作用域环境
  • 工厂函数返回的每个实例都有独立的状态
  • 合理使用闭包可以实现强大的功能增强
  • 注意内存管理和性能优化
http://www.lryc.cn/news/590816.html

相关文章:

  • 【Android】ViewBinding(视图绑定)
  • OpenCV中常用特征提取算法(SURF、ORB、SIFT和AKAZE)用法示例(C++和Python)
  • YOLOv3 技术深度解析:从理论到实践的完整指南
  • Linux的Ext系列文件系统
  • 深入理解进程等待:wait的简化与waitpid的灵活性
  • 力扣每日一题--2025.7.17
  • AndroidStudio环境搭建
  • openinstall上线SSL证书服务,开启数字安全新纪元
  • 使用Pytorch进行数字手写体识别
  • 细菌实验入门:浓度测定与菌种鉴定技术详解
  • AI搜索+GEO时代的营销策略更迭学习笔记
  • mapbox V3 新特性,添加模型图层
  • [yotroy.cool] 记一次 Git 移除某个不该提交的文件
  • 云手机的具体技术要求有什么?
  • 高光谱相机(Hyperspectral Camera)
  • 深度学习 -- 初步认识Torch
  • 卷积神经网络--网络性能提升
  • kong是什么
  • 线上项目https看不了http的图片解决
  • 数据结构 栈(2)--栈的实现
  • 图片上传实现
  • 性能优化的利器:SWC
  • Codeforces Round 1016 (Div. 3) A-F
  • 激活函数LeakyReLU
  • SM3算法工程中添加bouncycastle.bcprov.jdk15on库
  • 信息收集知识总结
  • 60个功能OfficeBox 万彩办公大师:PDF 格式转换 OCR识别免费无广告
  • 深入理解-Java-线程池:原理、动态调整与监控实践
  • 【SF顺丰】顺丰开放平台API对接(注册、API测试篇)
  • C#.NET BackgroundService 详解