JavaScript闭包的10个实用场景从入门到精通

# 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开发中的强大应用,从基础的数据封装到高级的异步编程模式。掌握这些模式将帮助你编写更模块化、可维护和高效的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值