闭包的应用场景一

本文探讨了闭包的概念及其在避免全局变量污染、在函数间传递参数、提前提供函数参数等方面的用法。通过实例展示了如何使用闭包代替全局变量,解决在Ajax回调、函数参数延迟提供等场景中的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[Don't use closures unless you really need closure  semantics.]不要使用闭包,除非你真正需要它。

[In most cases, non-nested functions are the right way to go.]请使用无嵌套函数。

闭包的应用场景一

闭包的应用场景二

闭包的应用场景三

-------------------------------------------

什么是闭包?


  
function a(){
var i = 0 ;
function b(){
alert(i);
}
return b;
}
var c = a();
c();

全局变量c指定对 函数a的内部函数b的引用;内部函数b的执行需要依赖函数a的资源;

这里就产生一个闭包,使得a在执行完毕并返回后,不会被javascript垃圾回收机制GC回收。

因为这里c还在引用着b,而b依赖着a,故a在使用后,仍然存在于内存中。

简而言之:当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。

 

闭包的应用场景

  1.使用闭包代替全局变量

  2.函数外或在其他函数中访问某一函数内部的参数

  3.在函数执行之前为要执行的函数提供具体参数

  4.在函数执行之前为函数提供只有在函数执行或引用时才能知道的具体参数

     5.为节点循环绑定click事件,在事件函数中使用当次循环的值或节点,而不是最后一次循环的值或节点

     6.暂停执行

     7.包装相关功能

1.使用闭包代替全局变量

   全局变量有变量污染和变量安全等问题。


  
// 全局变量,test1是全局变量
var test1 = 111
function outer(){
alert(test1);
}
outer();
// 111
alert(test1); // 111
 
 

// 闭包,test2是局部变量,这是闭包的目的
//
我们经常在小范围使用全局变量,这个时候就可以使用闭包来代替。
( function (){
var test2 = 222 ;
function outer(){
alert(test2);
}
function test(){
alert(
" 测试闭包: " + test2);
}
outer();
// 222
test(); // 测试闭包:222
}
)();
alert(test2);
// 未定义,这里就访问不到test2

  

2.函数外或在其他函数中访问某一函数内部的参数

   为了解决在Ajax callback回调函数中经常需要继续使用主调函数的某一些参数。


  
function f1(){
var test = 111 ;
tmp_test
= function (){ return test;} // tmp_test是全局变量,这里对test的引用,产生闭包
}

function f2(){
alert(
" 测试一: " + tmp_test());
var test1 = tmp_test();
alert(
" 测试二: " + test1);
}
f1();
f2();
// 测试一:111
//
测试二:111
alert(tmp_test()); // 111
tmp_test = null ;

  

3.在函数执行之前为要执行的函数提供具体参数

某些情况下,是无法为要执行的函数提供参数,只能在函数执行之前,提前提供参数。

有哪些情况是延迟执行?

如:setTimeOut 

     setInterval

     Ajax callbacks

     event handler[el.onclick=func 、 el.attachEvent("onclick",func)]


  
// 无法传参的情况
var parm = 222 ;
function f1(){alert( 111 )}
function f2(obj){alert(obj)}
setTimeout(f1,
500 ); // 正确,无参数
var test1 = f2(parm); // 执行一次f2函数
setTimeout(f2, 500 ); // undefined,传参失败
setTimeout(f2(parm), 500 ); // 参数无效,传参失败
setTimeout( function (parm){alert(parm)}, 500 ); // undefined,传参失败
document.getElementById( " hello " ).onclick = f1; // 正确
document.getElementById( " hello " ).attachEvent( " onclick " ,f1); // 正确
 

// 正确做法,使用闭包
function f3(obj){ return function (){alert(obj)}}
var test2 = f3(parm); // 返回f3的内部函数的引用
setTimeout(test2, 500 ); // 正确,222
document.getElementById( " hello " ).onclick = test2; // 正确,222
document.getElementById( " hello " ).attachEvent( " onclick " ,test2); // 正确,222

 

### 闭包的实际应用案例 #### 定时器和延迟执行 在 JavaScript 中,定时器经常利用闭包来保存状态。例如,在 `setTimeout` 或 `setInterval` 的回调函数中访问外部作用域的变量是种典型的闭包应用场景[^3]。 ```javascript function setupTimer() { let count = 0; setTimeout(function timer() { console.log(count++); // 访问并修改外部变量count if (count < 5) { setTimeout(timer, 1000); } }, 1000); } setupTimer(); ``` 上述代码展示了如何通过闭包让计数器持续运行段时间,并且能够记住上次的状态[^4]。 #### 防抖与节流(Debouncing & Throttling) 防抖和节流是前端性能优化的重要技术之,它们通常依赖于闭包实现内部状态管理。以下是个简单的防抖函数示例: ```javascript function debounce(func, delay) { let timeoutId; return function (...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } const handleResize = debounce(() => console.log('Window resized'), 300); window.addEventListener('resize', handleResize); ``` 这里,`timeoutId` 被封闭在返回的新函数中,从而实现了对外部不可见的状态控制。 #### 模块模式(Module Pattern) 模块模式允许创建具有私有成员的对象结构,这正是借助闭包完成的。下面的例子展示了个简单模块的设计方式: ```javascript const CounterModule = (() => { let privateCount = 0; return { increment: () => ++privateCount, getCount: () => privateCount }; })(); console.log(CounterModule.getCount()); // 输出:0 CounterModule.increment(); console.log(CounterModule.getCount()); // 输出:1 ``` 此模式下,`privateCount` 不会被直接暴露给全局命名空间,仅能通过公开的方法间接操作它。 #### Vue.js 中的闭包运用 Vue 组件内的许多地方都涉及到了闭包的概念,比如计算属性、生命周期钩子以及事件处理器等。考虑如下情形: ```javascript export default { data() { return { message: 'Hello' }; }, computed: { reversedMessage() { const original = this.message; // 使用data中的message值 return original.split('').reverse().join(''); } } }; ``` 这里的 `reversedMessage` 是基于组件实例的数据动态生成的结果,而这种绑定关系本质上也是由闭包机制支持的。 #### 方法链设计 当构建复杂的 API 接口或者工具库时,可以通过闭包维持上下文对象的致性以便支持流畅接口风格。看这样个例子: ```javascript class QueryBuilder { constructor(query = '') { this.query = query; } select(field) { this.query += ` SELECT ${field};`; return this; } where(condition) { this.query += ` WHERE ${condition};`; return this; } build() { return this.query.trim(); } } const qb = new QueryBuilder(); const sqlQuery = qb.select('*').where('id > 10').build(); console.log(sqlQuery); // 输出完整的SQL语句字符串 ``` 每个方法调用之后仍然保留着当前查询构造器的状态直到最终组装完毕为止。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值