JavaScript闭包详解:原理、应用与常见问题处理

作者:函数茶馆

时间:2026-10-24

浏览:406

本文深入解析JavaScript闭包的定义、产生条件及执行时机,通过代码示例展示其作为实参传递、计数器封装等常见应用场景。同时探讨闭包在自定义模块封装中的价值,并针对this指向错误及内存泄露问题提供具体的解决方案,帮助开发者深入理解并安全使用闭包。

文章目录

前言

JavaScript中的闭包概念往往让初学者感到困惑。本文旨在从闭包的基本定义、典型示例、核心作用、实际应用场景以及常见陷阱等多个维度进行系统梳理,力求帮助读者建立对闭包的深入认知。文中如有疏漏或不当之处,欢迎指正交流。

一、什么是闭包?

闭包的本质是一个嵌套的内部(子)函数,它引用了父函数作用域中的数据,从而形成了闭包结构。

理解闭包需把握以下核心要点:

1. 必须存在函数的嵌套关系; 2. 闭包本身是一个函数,且特指那个嵌套的内部函数; 3. 该内部函数必须引用父函数作用域中的变量或数据。

若上述任一条件不满足,则无法形成闭包,下文将通过具体代码示例加以说明。

1.1 满足闭包条件的代码示例


<script>
			function person(){
				var name='marshal';
				function student(){ //声明子函数
					console.log(name);//引用父函数作用域的变量name
				}
			}
			person();//函数执行,产生闭包
		</script>      

前言

1.2 闭包的产生时机


	<script>
			function person(){
				var name='marshal';//js执行此行时,产生闭包
				function student(){ //声明子函数
					console.log(name);//引用父函数作用域的变量name
				}
				student();//内部函数在外部函数调用
			}
			person();//函数执行,虽满足闭包条件,但未产生闭包
		</script>

前言

闭包产生的确切时机是:当嵌套子函数的代码块引用了父函数作用域的数据,且该子函数即将执行、创建执行上下文时,闭包随之产生。简而言之,当嵌套子函数在外部被调用执行的那一刻,闭包即被创建。


<script>
			function person(){
				var name='marshal';
				function student(){
					console.log(name);  //该方法代码内为闭包代码
				}
				return student;
			}
			var p=person();//因创建子函数对像,此时产生第一次闭包,并将子函数student返回给p,由于p没有消失,子函数引用的变量name,一直在内存在存储,直到将p=null,进行回收
			p();//执行子函数的闭包代码块,输出"marhsal"
			p();//第二次执行子函数的闭包代码块,输出"marhsal"
			person();//第二次创建子函数调对象,此时产生第二次闭包,但不执行子函数student代码块      
		</script>

二、常见闭包示例

2.1 将子函数作为实参传递


<script>
			function setTimeoutTest(message,time){
				setTimeout(function(){
					alert(message);//嵌套子函数引用父函数变量message,产生闭包
				},time);
			}  
			setTimeoutTest('提示信息',1000);
		</script>

2.2 计数器实现(通过函数返回值)


<script>
				function count(){
					var i=1;
					function add(){
						i++;
						console.log(i);
					}
					return add;
				}
				var c=count();//生产闭包
				c();//2
				c();//3
				c();//4
		</script>

三、闭包的作用

3.1 闭包的主要作用

1)子函数引用父函数的变量或函数,从而延长其生命周期;

2)使得这些变量或函数在外部持续存在,允许外部访问函数内部的值。


<script>
			function count(){
				var i=1;
				function add(){
					i++;
					console.log(i);
				}
				return add;
			}
			var c=count();
			c();//2
			c();//3  i的生命周期延长
	</script>

四、闭包的应用

4.1 用于自定义封装JavaScript代码


外部js代码  out.js  实现自加与自减
(function count(){
	var i=1;
	function add(){
		i++;
		console.log(i);
	}
	function subtract(){
		i--
		console.log(i);
	}
	window.count={
		add:add,
		subtract:subtract
	}
})();

引用 out.js代码
<script src=out.js></script>
		<script>
			count.add(); //2
			count.subtract();//1
			count.subtract();//0
		</script>

五、闭包相关问题

5.1 闭包与this关键字的指向问题


<script>
     var name="marshal"; //创建全局变量
	 var person={
		 name:"leo",
		 getName:function(){ //返回匿名函数
			 return function(){  //返回this.name
				return this.name;  //返回字符串
			 }
		 }
	 };
	 alert(person.getName()()); //输出marshal,内部函数不可能直接访问外部函数this
	 
</script>

解决方法


<script>
	     var name="marshal";
			 var person={
				 name:"leo",
				 getName:function(){
					 var that=this;//把this保存到闭包可以访问的另一个变量中
					 return function(){
						return that.name;
					 }
				 }
			 };
			 alert(person.getName()());//that 指向person,而不是window
	</script>

5.2 内存泄露问题

在使用闭包时,由于引用的变量会一直驻留在内存中,需要注意及时解除对对象的引用。具体做法是将相关对象设置为null,从而确保其占用的内存在适当时候能够被垃圾回收机制回收。

至此,关于JavaScript闭包原理及其应用的详解已介绍完毕。如需了解更多相关JS闭包与应用内容,建议搜索本站历史文章或继续浏览后续相关教程。感谢大家的支持!

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章