JavaScript 闭包应用场景详解
闭包是JavaScript中一个强大且重要的概念,它指的是函数与其词法环境的组合,允许函数访问并记住其定义时的作用域。下面我将通过具体示例展示闭包的四个主要应用场景:
应用场景及示例
1. 封装私有变量(防抖/节流)
javascript
// 防抖函数(私有变量:timer)
function debounce(fn, delay) {
let timer = null; // 闭包保存的私有变量
return function() {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
};
}
// 节流函数(私有变量:lastTime)
function throttle(fn, interval) {
let lastTime = 0; // 闭包保存的私有变量
return function() {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, arguments);
lastTime = now;
}
};
}
// 使用示例
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce(function() {
console.log('搜索:', this.value);
}, 300));
window.addEventListener('scroll', throttle(function() {
console.log('滚动位置:', window.scrollY);
}, 200));
2. 实现单例模式
javascript
const Singleton = (function() {
let instance = null; // 闭包保存唯一实例
function createInstance() {
return {
id: Math.random().toString(36).substr(2, 9),
createdAt: new Date()
};
}
return {
getInstance: function() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
// 使用示例
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // true
console.log('实例ID:', instance1.id);
3. 柯里化函数
javascript
// 柯里化函数
function curry(fn) {
const arity = fn.length;
return function curried(...args) {
if (args.length >= arity) {
return fn.apply(this, args);
} else {
return function(...moreArgs) {
return curried.apply(this, args.concat(moreArgs));
};
}
};
}
// 使用示例
const multiply = (a, b, c) => a * b * c;
const curriedMultiply = curry(multiply);
console.log('结果1:', curriedMultiply(2)(3)(4)); // 24
console.log('结果2:', curriedMultiply(2, 3)(4)); // 24
console.log('结果3:', curriedMultiply(2)(3, 4)); // 24
4. 缓存计算结果(记忆函数)
javascript
// 记忆函数
function memoize(fn) {
const cache = {}; // 闭包保存计算结果缓存
return function(...args) {
const key = JSON.stringify(args);
if (cache[key] !== undefined) {
console.log('从缓存获取结果');
return cache[key];
}
console.log('执行计算');
const result = fn.apply(this, args);
cache[key] = result;
return result;
};
}
// 使用示例
function fibonacci(n) {
if (n <= 1) return n;
return fibonacciMemo(n - 1) + fibonacciMemo(n - 2);
}
const fibonacciMemo = memoize(fibonacci);
console.log('fib(10):', fibonacciMemo(10)); // 计算10次
console.log('fib(10):', fibonacciMemo(10)); // 从缓存获取
console.log('fib(11):', fibonacciMemo(11)); // 只计算1次(利用缓存结果)
闭包原理说明
闭包的核心原理是函数可以记住并访问其词法作用域,即使函数在其词法作用域之外执行。这种机制使得函数可以:
- 访问定义时的作用域变量
- 维护私有状态
- 封装数据和功能
- 创建模块化的代码结构
graph TD
A[外部函数] --> B[定义内部函数]
B --> C[内部函数引用外部变量]
A --> D[返回内部函数]
D --> E[外部函数执行结束]
E --> F[内部函数仍可访问外部变量]
闭包应用总结表
应用场景 | 闭包作用 | 示例说明 | 关键优势 |
---|---|---|---|
封装私有变量 | 保存状态 | 防抖/节流中的定时器变量 | 避免全局污染,保护数据 |
单例模式 | 保存唯一实例 | 只创建一个全局共享实例 | 节省资源,控制访问 |
柯里化函数 | 保存部分参数 | 分步传递参数,延迟执行 | 函数组合,代码复用 |
缓存计算结果 | 保存计算结果缓存 | 记忆函数避免重复计算 | 提高性能,优化计算 |
闭包是JavaScript编程中的强大工具,理解并掌握它可以显著提高代码质量和开发效率。