什么是闭包?
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); // 清除数组中的clearKey
const clearData = cache[clearKey]; // 保留被清除的数据,用于return
delete 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:'https://blog.csdn.net/li459559937?spm=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:'https://blog.csdn.net/li459559937?spm=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 回收机制,有兴趣的童鞋可以去了解了解。
题外话:缓存机制
既然前面有例子写到了缓存机制,那么也简单的了解一下。
对于缓存机制来说,也可以使用localStorage来实现,但是各有有缺点吧。
localStorage的优缺点- 优点:
- 数据存于浏览器缓存中,可以同域名下,跨tab界面数据交互
- 存储时间长,关闭浏览器也不会被清除掉
- 存储大小可达5M
- 缺点:
- 任何数据储存后,都会被转化成字符串
- 手动清除浏览器缓存后就会被销毁
- 适合缓存简单型数据,单、多页面应用均可以使用
闭包的缓存机制
- 优点:
- 可以储存javascript的任何形态数据,且不会被转化
- 手动浏览器清除缓存也不影响
- 缺点:
- 无法跨tab界面数据交互
- 存储时间短,关闭tab页后就会被销毁
- 存在javascript内存中,缓存过多数据可能会影响性能,严重的导致内存溢出
- 适合:适合缓存少量复杂型数据,单界面应用
关于localStorage的使用请参考:Window localStorage 属性
版权声明:本文为li459559937原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。