欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

03.JS进阶——闭包

程序员文章站 2024-03-17 16:39:10
...

 

function myModule(){
	//私有数据
	var msg = 'my atguigu'
	//操作数据的函数
	function doSomething(){
		//换大写
		console.log('doSomething()'+msg.toUpperCase())
	}
	function doOtherthing(){
		//换小写
		console.log('doOtherthing()' +msg.toLowerCase())
	}
	//当暴露单个的时候
	//return doSomething()
	//暴露两个的时候(暴露对象 给外界暴露使用的方法)
	return {
		doSomething:doSomething,
		doOtherthing:doOtherthing
	}
	
}

(function(){
	//私有数据
	var msg = 'my atguigu'
	//操作数据的函数
	function doSomething(){
		//换大写
		console.log('doSomething()'+msg.toUpperCase())
	}
	function doOtherthing(){
		//换小写
		console.log('doOtherthing()' +msg.toLowerCase())
	}
	//当暴露单个的时候
	//暴露两个的时候(暴露对象 给外界暴露使用的方法)
	window.myModule2 = {
		doSomething:doSomething,
		doOtherthing:doOtherthing
	}	
})()










 2.了解闭包

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<!--
			1.如何产生闭包?
				* 当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包
			2.闭包到底是什么?
				* 使用Chrome调试看看
				* 理解一:闭包是嵌套的内部函数(绝大部分人)
				* 理解二:包含被引用变量(函数)的对象(极少数)、
				* 注意:闭包存在于嵌套的内部函数中
			3.产生闭包的条件
				* 函数嵌套
				* 内部函数引用了外部函数的数据(变量/函数)
			
			
			
			
			
		-->
		<script type="text/javascript">
			
			function fn1(){
				var a = 2
				var b = 'abc'
				function fn2(){//执行函数定义的时就会产生闭包(不用调用内部函数)
					console.log(a)
				}
				fn2()
			}
			fn1()
			//var fn2 = function() 这样还没执行函数定义
		</script>
		
		
		
	</body>
</html>

3.常见的闭包

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<!--
			1. 将函数作为另一个函数的返回值
			2. 将函数作为实参传递给另一个函数调用
		-->
		<script type="text/javascript">
			function fn1(){
				var a = 2;
				function fn2(){//只产生了一次的闭包:函数执行定义只产生了一次
					a++
					console.log(a)
				}
				return fn2
			}
			var f = fn1()//闭包的产生和函数调用的次数和外部调用函数有关,和还有引用变量
			f()//3
			f()//4
			
			
			//2.将函数作为实参传递给另一个函数调用
			
			function showDelay(msg,time){
				setTimeout(function(){
					alert(msg)
				},time)
			}
			showDelay('atguigu',2000)
			
			
		</script>
		
		
		//return 接收结果 并且返回给当前位置的参数
	</body>
</html>

4.闭包的作用

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<!--
			1. 使用函数内部的变量在执行完后,仍然存活在内存当中(延长了局部变量的生命周期)
			2. 让函数 外 部可以操作(读写)到函数 内 部的数据(变量/函数)
		
		问题:
			1. 函数在执行完后,函数内部声明的局部变量是否还存在? 一般情况是不存在的 只有闭包存在的时候 才会存在
			2. 在函数外部能直接访问函数内部的局部变量吗? 不能直接访问,但是我们可以通过闭包让外部 (操作它)  进行访问内部的数据。
			
		-->
		
		<script type="text/javascript">
			
			function fn1(){
				var a = 2;
				function fn2(){//只产生了一次的闭包:函数执行定义只产生了一次
					a++
					console.log(a)
				}
				//return fn2//暴露出去
				function fn3(){
					a--
					console.log(a)
				}
				return fn3
			}
			var f = fn1()//闭包的产生和函数调用的次数和外部调用函数有关,和还有引用变量
			f()//3    //1
			f()//4    //0
			
			
			//return:将fn3暴露出去遇到a
			
		</script>
		
		<!--
			总结:
				   通过闭包能够让外部的函数操作内部的函数
				   之前没有闭包之前 是不可以这样操作的
			
		-->

		
		
		
		
		
		
		
		
		
	</body>
</html>

5.闭包的生命周期

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<!--
			1. 产生:在嵌套内部函数定义执行完时就产生了(不是在调用)
			2. 死亡:在嵌套的内部函数成为垃圾对象的时
					
		-->
		<script type="text/javascript">
			function fn1(){
				var a = 2;//闭包已经产生了(因为函数提升,内部函数对象已经创建了)
				function fn2(){//这是函数定义执行      <两个不一样>
					//var fn2 = function(){} 函数执行完毕才能产生闭包
					a++
					console.log(a)
				}
				return fn2
			}
			var f = fn1()//闭包已经产生
			f()//3
			f()//4	
		//f = null 闭包死亡  包函那个闭包的函数成为了垃圾对象
		</script>
	</body>
</html>

6.闭包的应用__自定义JS模块1

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>闭包自定义JS模块</title>
	</head>
	<body>
		<!--
			闭包的应用:定义JS模块
				* 具有特定功能的js文件
				* 将所有的数据和功能都封装在一个函数内部(私有的)
				* 只向外暴露一个包含n个方法的对象或函数
				* 模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
		-->
		<script type="text/javascript" src="js/myModule.js"></script>
		<script type="text/javascript">
			var fn = myModule()
			//fn()//输出:doSomething() MY ATGUIGU 暴露单个的时候
			
			fn.doSomething()//doSomething() MY ATGUIGU
			fn.doOtherthing()//doOtherthing my atguigu
			
		</script>
	</body>
</html>

7.闭包的应用__自定义JS模块2

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>闭包自定义JS模块</title>
	</head>
	<body>
		<!--
			闭包的应用:定义JS模块
				* 具有特定功能的js文件
				* 将所有的数据和功能都封装在一个函数内部(私有的)
				* 只向外暴露一个包含n个方法的对象或函数
				* 模块的使用者,只需要通过模块暴露的对象调用方法来实现对应的功能
		-->
		<script type="text/javascript" src="js/myModule2.js"></script>
		<script type="text/javascript">
//			var fn = myModule()
//			//fn()//输出:doSomething() MY ATGUIGU 暴露单个的时候
//			
//			fn.doSomething()//doSomething() MY ATGUIGU
//			fn.doOtherthing()//doOtherthing my atguigu
//使用window 直接让他们两个成为它的属性 然后就可以被看见 所以就可以直接使用
			myModule2.doSomething()
			myModule2.doOtherthing()
			
		</script>
	</body>
</html>

8.闭包的缺点以及解决

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<!--
			1. 缺点
			* 函数执行完后,函数内的局部变量没有释放,占用内存时间变长
			* 容易造成内存的泄露
			2. 解决
			* 能不用闭包就不用
			* 及时释放
			
			
			
			
		-->
		
		<script type="text/javascript">
			
			function fn1(){
				var arr = new Array[100]
				function fn2(){
					console.log(arr.length)
				}
				return fn2
			}
			var f = fn1()
			f()
			
			//释放内存:让内部函数成为垃圾对象 -->回收闭包
			f = null
			
		</script>
		
		
		
	</body>
</html>

9.面试题02(练习)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			//代码片段一
			var name = "外部name";
			var object = {
				name : "内部的name";
				getfunname : function(){
					return function(){
						return this.name;
					};
				}
				
			};
			alert(object.getNameFunc()());
			
			
			//代码片段二
			var name2 = "外部的name"
			
			var object2 = {
				name2 : '内部的name'
				var that = this;
				getNameFunc2 : function(){
					return function(){
						return that.name2;
					};
				}
				
			};
			alert(object.getNameFunc2()());
			
			
		</script>
	</body>
</html>

10.面试题1

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			//代码片段一
			var name = "the Window"
			var object ={
				name : "My Object",
				getNameFunc : function(){
					return function(){
						return this.name;
					};
				}
			};
			alert(object.getNameFunc()());//the Window
			
			//理解:object调用函数 函数体中的this是window  直接指向全局变量的name
			
			//有无闭包:1.内部函数的嵌套 2.内部函数引用函数外部函数的变量
			
			
			
			
			//代码片段二
			var name2 = "the Window"
			var object2 ={
				name2 : "My Object",
				getNameFunc : function(){
					var that = this;
					return function(){
						return that.name2;
					};
				}
			};
			alert(object2.getNameFunc()());//My Object
			
			//结论:使用this.name中 this是window 所以这里是使用之前就把object2(this)赋值给that 所以这里只能是object2
			
			//有:闭包(that保存起来):函数的嵌套  内部函数引用了外部函数的嵌套
			
			
			
		</script>
	</body>
</html>

11.面试题2

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			function fun(n,o){
				console.log(o)//如果闭包 不产生新的 那么就会一直都是这个数
							  //只有产生新的闭包 我们才能说闭包的值发生改变
				return {
					fun:function(m){
						return fun(m,n);
					}
				};
			}
			//调用外部函数产生闭包 调用内部函数不产生闭包
			var a = fun(0);//变量提升 undefined 
			a.fun(1);//0
			a.fun(2);//0
			a.fun(3);//0
			
			var b = fun(0).fun(1).fun(2).fun(3)
			
			var c = fun(0).fun(1);
			c.fun2();
			c.fun(3);
			
			
			
			
		</script>
	</body>
</html>

12.内存溢出与泄漏

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		
		<!--
			1. 内存溢出
			   * 一种程序运行出现的错误
			   * 当程序运行需要的内存超过了剩余的内存时,或出抛出溢出的错误
			2. 内存泄露
			   * 占用了内存没有及时释放
			   * 内存泄露积累多了就容易导致内存退出
			   * 常见的内存泄露:
			   		* 意外的全局变量
			   		* 没有及时清理的计时器或回调函数
			   		* 闭包
		-->
		<script type="text/javascript">
			// 1. 内存溢出
			var obj = {}
			for (var i = 0; i <1000; i++) {
				obj[i] = new Array(100000)//obj是一个伪数组 将array放入obj中
				console.log('------')
				//结果:当程序运行的内存超过电脑运行的内存的时候 会出现内存溢出(网站崩溃啦!!!就是一个)
			}
			//2.内存泄露
			//意外的全局变量
			function fn(){
				a = 3//没有定义就是全局变量,小的时候不会 大的时候 a = new Array(10000000000)
				console.log(a)
			}
			fn()
		
			//2. 没有及时清理的计时器或回调函数
			var intervaId = setInterval(function(){//启动循环定时器后不清理
				console.log('------------------')
			},1000)
		
			//不使用的时候可以使用clearInterval()清理
			clearInterval(intervaId)//intervaId 标识传进
		
			//3. 闭包
			function fn1(){
				var a =4
				function fn2(){
					console.log(++a)
				}
				return fn2
			}
			var f = fn1()
			f()
		//含有闭包 内存无法释放
		//解决办法:
		//f = null
		
		
		</script>
		
		<!--
			总结:
			内存溢出 :指的是程序运行的内存超出了电脑的运行内存 然后导致内存溢出
			内存泄露 :指的是程序的内存泄露了 导致电脑内存变少 而程序的内存大于电脑的 就叫内存泄露
			
			
			
			
		-->
		
		
		
		
		
		
		
	</body>
</html>