什么是闭包?

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 回收机制,有兴趣的童鞋可以去了解了解。
js 闭包的理解和运用什么是闭包?什么是闭包?1、闭包让你可以在一个内层函数中访问到其外层函数的作用域。引用于:MDN2、闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。引用于:菜鸟教程...
关于闭包理解闭包之前,为了让大家更好的理解闭包,我举一个形象的例子。在JS里有着作用域的概念,那么作用域是什么呢?有什么用呢?下面这个例子能形象的体现 比如每一座城市,城市里乡镇啊有公园,超市等,这些建筑设施就构建了这一个城市(环境),那么这些环境构成的依据是什么呢?是有人依赖它,用它。当这个城市的的人迁出这个城市,那么这个城市没有人再依赖他,那么它的存在就没有意义了, 总的来说当这个城市(环境)不再被需要,它就被回收销毁掉,环境存在的前提是被需要 举一个例子,下面代码,重复调用能实现输出num的累加吗? function fn1(){ var num = 1; function f
我研究JavaScript闭包(closure)已经有一段时间了。我之前只是学会了如何使用它们,而没有透彻地了解它们具体是如何运作的。那么,究竟什么是闭包?Wikipedia给出的解释并没有太大的帮助。闭包是什么时候被创建的,什么时候被销毁的?具体的实现又是怎么样的?现在,我终于知道了答案,我感到很兴奋并且决定向大家解释这个答案。至少,我一定是不会忘记这个答案的。并且,在我阅读与闭包相关的现存的资料时,我很努力地尝试着去在脑海想想每个事物之间的联系:对象之间是如何引用的,对象之间的继承关系是什么,等等。我找不到关于这些负责关系的很好的图表,于是我决定自己画一些。我将假设读者对JavaScri
它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域的任何局部变量组成。 这种官方的概念是比较难理解的,在面试的时候说出来也不是很专业,因为没办法有个具体的逻辑。 我个人认为,理解闭包的关键在于:外部函数调用之后其变量对象本应该被销毁,但... 闭包是一个封闭的空间,里面存储了在其他地方会引用到的该作用域的值 在 javascript 是通过作用域链来实现的闭包。 只要在函数使用(访问)了外部(作用域链上前面的作用域)的数据,就创建了闭包!!! 但是这种情况下所创建的闭包,我们在编码时是不需要关心的。 我们还可以手动的创建闭包,让外部环境访问函数内部的局部变量,这样就可以让函数内部的局部变量保存下来,不会被垃圾回收。 应用场景: 可以解决全局环境变量污染的问题,让外部环境可以.
形成闭包的条件: 1、一个不会被销毁函数执行空间(解释:当一个一个函数return返回一个复杂数据类型的时候就表示是一个不被销毁函数执行空间(当是返回简单数据类型的时候不会形成这种销毁空间)) 2、函数内部 直接 或者 间接 的返回一个函数 ; 3、内部函数操作(访问,赋值)着外部函数变量 当以上个三个函数满足时 我们管内部的函数叫做外部函数闭包函数 销毁闭包 : 就是把 返回出来的函数 重新赋值 例如 res = null 这样闭包就会被销毁
闭包是一个可以访问外部作用域变量的内部函数。这些被引用的变量直到闭包销毁时才会被销毁。在本质上是函数内部和函数外部链接的桥梁。不会触发垃圾回收机制。 闭包属于一种特殊的作用域,称为静态作用域。它的定义可以理解为: 父函数销毁的情况下,返回出的子函数的[[scope]]仍然保留着父级的单变量对象和作用域链,因此可以继续访问到父级的变量对象,这样的函数称为闭包闭包会产生一个很经典的问题: 多个子函数的[[scope]]都是同时指向父级,是完全共享的。因此当父级的变 量对象被修改时,所有子函数都受到
闭包——形成私有作用域,让私有变量存到内存里面,保护私有变量,让其不受外界的影响。 闭包的作用:使在外层作用域下可以访问到内层作用域下的变量 闭包的弊端:不建议大量使用闭包闭包变量存到内存里边,会导致内存泄漏,或者页面的性能问题。 解决方案:在闭包使用完之后将私有变量删除delete(适用于IE浏览器),或将闭包对应的变量置空(适用于大多数现代浏览器),如下例的 result=null; 以下是三个简单的闭包,帮助理解闭包的含义: function fn1() {
JavaScript闭包是指函数可以访问其外部作用域变量,即使函数在外部作用域之外被调用。这是因为函数在创建时会创建一个闭包,它包含了函数的代码和函数所在的作用域。当函数被调用时,它可以访问闭包变量,即使这些变量函数外部也可以被访问。 闭包JavaScript非常常见,它们可以用于创建私有变量和方法,以及在异步编程保存状态。但是,使用闭包也可能会导致内存泄漏和性能问题,因此需要谨慎使用。深入理解JavaScript闭包可以帮助我们更好地理解JavaScript的工作原理,并且能够更好地编写高效的代码。