javascript 闭包的理解、运用和销毁

时间: 2024-11-10 admin IT培训

javascript 闭包的理解、运用和销毁

javascript 闭包的理解、运用和销毁

javascript 闭包的理解和运用

      • 什么是闭包?
      • 闭包的理解
      • 闭包的运用
      • 闭包的销毁

什么是闭包?

1、闭包让你可以在一个内层函数中访问到其外层函数的作用域。引用于:MDN-闭包
2、闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。直观的说就是形成一个不销毁的栈环境。引用于:菜鸟教程-JavaScript 闭包
PS:看看就好,看不懂也没关系

闭包的理解

比较直白的来理解闭包概念:

  • 形成闭包的条件:
    • 内外2层函数
    • 内部函数中使用了父函数的变量
    • 内部的私有变量外界可以引用,但无法改变,且不轻易被销毁

下面来看代码:

	// 外层函数const outerFn = () => {// 私有变量,可以通过内层函数访问,但无法被外界干预let count = 0;// 内层函数const innerFn = () => {console.log('内部count', count++); // 使用了父函数的变量return count;}return innerFn;}const closure = outerFn(); // 这就是一个闭包console.log('返回的count', closure());console.log('返回的count', closure());// 输出结果:// 内部count 0// 返回的count 1// 内部count 1// 返回的count 2

根据结果看出:

  • 可通过closure()来获取count的值
  • 执行多次closure()时,count的值并不会被重置为0,而是持续叠加,证明outerFn内的私有变量count并不会随着执行closure()后被销毁。

闭包的运用

根据私有变量保护机制、且不易销毁的特性,可运用于缓存机制

// A.JS
window.caCheDataBox = ()=>{let cache = {}; // 缓存数据let cacheKeys = []; // 数据映射的key值const maxCacheCount = 20; // 为了防止内存溢出,规定最大缓存数据数量return {/** 缓存数据* key {string} 映射数据的值* data {any} 需要缓存的数据*/setCache:(key, data)=>{// 判断key值是否已存在if(key in cache){cache[key] = data;}else{cacheKeys.push(key);// 判断已缓存的数据数量是否大于规定最大数量if(cacheKeys.length > maxCacheCount){const delKey = cacheKeys.shift(); // 删除第一个key,保持先进先出delete cache[delKey]; // 删除对应的缓存数据}cache[key] = data;}},/** 获取映射缓存数据* key {string} 根据key值,获取映射的数据* @return 缓存数据 | null*/getCache:(key)=>{if(key in cache){return cache[key];}return null;},/** 清除映射缓存数据* key {string} 根据key值,清除映射的数据* @return 被清除的数据*/clearCache:(clearKey)=>{if(clearKey in cache){const keyIndex = cacheKeys.findIndex(val=>val===clearKey); // 获取key值的下标cacheKeys.splice(keyIndex, 1); // 清除数组中的clearKeyconst clearData = cache[clearKey]; // 保留被清除的数据,用于returndelete cache[clearKey]; // 清除对应的缓存数据return clearData;}return null;},/** 获取全部缓存数据*/getAllCache:()=>{return cache;},/** 清除全部缓存数据,并返回全部缓存数据*/clearAllCache:()=>{const caCheData = cache; cache = {};cacheKeys = [];return caCheData;}};
}(); // 立即执行匿名函数

封装好后,一般使用方法:

// B.JS
// 缓存登陆信息
const ajaxUser = new Promise((resove)=>{// 模拟接口请求setTimeout(()=>{resove({name:'李子玅',url:'=1011.2124.3001.5343'});}, 3000);
});// 初始化数据
ajaxUser.then((data)=>{caCheDataBox.setCache('userInfo',data); // 缓存用户数据
});
// C.JS
// 获取缓存的用户信息
const userInfo = caCheDataBox.getCache('userInfo');
console.log('userInfo',userInfo);
// 输出结果:
// userInfo {name:'李子玅',url:'=1011.2124.3001.5343'}
// D.JS
// 用户登出,清除用户信息
caCheDataBox.clearCache('userInfo');

其他例子我就不写了,基本都涵盖在上面的例子中了。用法和原理都是差不多的。
具体可参考:MDN-闭包

闭包的销毁

	const outerFn = () => {let count = 0;const innerFn = () => {console.log('count', ++count);}return innerFn;}let closure = outerFn(); // 创建第一个闭包closure();closure();closure = outerFn(); // 销毁第一个闭包,创建第二个闭包closure();closure();closure = null; // 销毁闭包// 输出结果:// count 1// count 2// count 1// count 2

由上面的例子可以看出来,当第二次为closure赋值后,再次执行2次closure()时,count的结果并不会变成3,4,而是又变回了1,2
这表示着,当第二次赋值的时候,第一个闭包就会被垃圾回收销毁掉,而第三次赋值为null时,则是把第二次的闭包也销毁了。

简单的总结:

  • 关于闭包的销毁
    • 可在模块或应用结束后来进行空赋值处理,进行销毁,比如上面的:closure = null
    • 等待页面被关闭,才会被销毁。
  • 至于为什么会要这么处理才会被销毁呢?具体的话可以网上找一下 javascript 回收机制,有兴趣的童鞋可以去了解了解。