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); // 清除数组中的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 回收机制,有兴趣的童鞋可以去了解了解。

你可能感兴趣的:(JavaScript,javascript,函数闭包,js)