# JavaScript闭包的10个实用场景:从入门到精通
## 1. 数据封装和私有变量
闭包最常见的用途是实现数据的封装,创建私有变量:
```javascript
function createCounter() {
let count = 0; // 私有变量
return {
increment: function() {
count++;
return count;
},
decrement: function() {
count--;
return count;
},
getValue: function() {
return count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
// console.log(counter.count); // undefined - 无法直接访问
```
## 2. 函数工厂
使用闭包创建具有特定行为的函数:
```javascript
function createMultiplier(multiplier) {
return function(x) {
return x multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
```
## 3. 事件处理中的状态保持
在事件处理程序中保持状态:
```javascript
function setupButtons() {
let clickCount = 0;
document.getElementById('myButton').addEventListener('click', function() {
clickCount++;
console.log(`按钮被点击了 ${clickCount} 次`);
this.textContent = `已点击: ${clickCount}`;
});
}
setupButtons();
```
## 4. 模块模式
实现模块化的代码组织:
```javascript
const myModule = (function() {
let privateVariable = '私有数据';
function privateMethod() {
console.log('这是一个私有方法');
}
return {
publicMethod: function() {
console.log('公共方法可以访问: ' + privateVariable);
privateMethod();
},
setData: function(data) {
privateVariable = data;
}
};
})();
myModule.publicMethod(); // 可以访问私有数据和方法
// myModule.privateMethod(); // 错误:私有方法不可访问
```
## 5. 记忆化(Memoization)
优化函数性能,缓存计算结果:
```javascript
function memoize(fn) {
const cache = {};
return function(...args) {
const key = JSON.stringify(args);
if (cache[key]) {
console.log('从缓存返回结果');
return cache[key];
}
console.log('计算新结果');
const result = fn.apply(this, args);
cache[key] = result;
return result;
};
}
// 使用示例
const expensiveCalculation = memoize(function(n) {
let result = 0;
for (let i = 0; i < n; i++) {
result += i;
}
return result;
});
console.log(expensiveCalculation(1000000)); // 计算新结果
console.log(expensiveCalculation(1000000)); // 从缓存返回结果
```
## 6. 循环中的闭包
解决循环中变量捕获的经典问题:
```javascript
// 错误的方式 - 所有回调都引用同一个i
function problemExample() {
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i); // 全部输出5
}, 100);
}
}
// 正确的方式 - 使用闭包创建新的作用域
function solutionExample() {
for (var i = 0; i < 5; i++) {
(function(j) {
setTimeout(function() {
console.log(j); // 分别输出0,1,2,3,4
}, 100);
})(i);
}
}
// 使用let的现代方式(本质上也是闭包)
function modernSolution() {
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i); // 分别输出0,1,2,3,4
}, 100);
}
}
```
## 7. 柯里化函数(Currying)
创建可部分应用的函数:
```javascript
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
};
}
};
}
// 使用示例
function add(a, b, c) {
return a + b + c;
}
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 6
console.log(curriedAdd(1, 2)(3)); // 6
console.log(curriedAdd(1)(2, 3)); // 6
const addFive = curriedAdd(5);
console.log(addFive(10, 15)); // 30
```
## 8. 状态管理
管理复杂的状态逻辑:
```javascript
function createState(initialState) {
let state = initialState;
const listeners = [];
return {
getState: function() {
return state;
},
setState: function(newState) {
const oldState = state;
state = typeof newState === 'function' ? newState(state) : newState;
// 通知所有监听器
listeners.forEach(listener => listener(state, oldState));
},
subscribe: function(listener) {
listeners.push(listener);
// 返回取消订阅的函数
return function() {
const index = listeners.indexOf(listener);
if (index > -1) {
listeners.splice(index, 1);
}
};
}
};
}
// 使用示例
const store = createState({ count: 0, name: '初始状态' });
const unsubscribe = store.subscribe((newState, oldState) => {
console.log('状态变化:', oldState, '->', newState);
});
store.setState({ count: 1, name: '更新状态' });
store.setState(prevState => ({ ...prevState, count: prevState.count + 1 }));
unsubscribe(); // 停止监听
```
## 9. 防抖和节流
优化高频事件处理:
```javascript
// 防抖:在事件停止触发后执行
function debounce(fn, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
// 节流:在一定时间间隔内只执行一次
function throttle(fn, delay) {
let lastCall = 0;
return function(...args) {
const now = Date.now();
if (now - lastCall >= delay) {
lastCall = now;
fn.apply(this, args);
}
};
}
// 使用示例
const debouncedSearch = debounce(function(query) {
console.log('搜索:', query);
}, 300);
const throttledScroll = throttle(function() {
console.log('滚动处理');
}, 100);
// 输入框搜索
document.getElementById('search').addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});
// 滚动事件
window.addEventListener('scroll', throttledScroll);
```
## 10. 异步编程中的状态保持
在异步操作中保持上下文:
```javascript
function createAsyncProcessor() {
let processing = false;
let queue = [];
async function processNext() {
if (processing || queue.length === 0) return;
processing = true;
const { data, resolve, reject } = queue.shift();
try {
// 模拟异步操作
const result = await fetchData(data);
resolve(result);
} catch (error) {
reject(error);
} finally {
processing = false;
processNext(); // 处理下一个
}
}
async function fetchData(data) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(`处理结果: ${data}`);
}, 1000);
});
}
return function addToQueue(data) {
return new Promise((resolve, reject) => {
queue.push({ data, resolve, reject });
processNext();
});
};
}
// 使用示例
const processor = createAsyncProcessor();
// 顺序处理多个请求
processor('任务1').then(console.log);
processor('任务2').then(console.log);
processor('任务3').then(console.log);
```
这些场景展示了闭包在JavaScript开发中的强大应用,从基础的数据封装到高级的异步编程模式。掌握这些模式将帮助你编写更模块化、可维护和高效的代码。
1080

被折叠的 条评论
为什么被折叠?



