深入理解JS闭包

291 阅读2分钟

产生闭包的条件

内层函数可以访问到外层函数的作用域。

function init() {
    var name = "Mozilla"; // name 是一个被 init 创建的局部变量
    function displayName() { // displayName() 是内部函数,一个闭包
        alert(name); // 使用了父函数中声明的变量
    }
    displayName();
}
init();//控制台运行结果:Mozilla
//

闭包的作用

  1. 使函数内部的变量在函数执行完后仍然存在于内存中(延长局部变量的生命周期)
  2. 使外部函数能够操作到内部函数的变量或函数

``

function foo(){
	var a=3;
	function b(){
		a++;
		console.log(a)
	}
	function c(){
		a--;
		console.log(a)
	}
	return c;
}
foo()();//控制台执行结果:2

闭包的生命周期

闭包的产生:内部嵌套函数定义执行完成后产生。

闭包的死亡:内部嵌套函数成为垃圾对象时

闭包的应用

  • 具有特定功能的js文件
  • 将所有的数据和功能都封装在函数内部私有的
  • 只向外暴露一个包含n个方法的对象或函数
  • 模块的使用者只需要调用暴露的对象调用方法来实现对应功能

方式1

//下面是js文件内部代码,文件名:myModule.js
function muModule(){
//私有
var msg='My atguigu'
funtion doSomething(){
  console.log('doSomething()'+msg.toUpperCase())
  //
 }
 funtion.doOtherthing(){
 console.log('doOtherthing()’+msg.toLowerCase())
 
 }
  return{
  doSomething: doSomething,
  doOtherthing: doOtherthing
  }//只向外暴露一个包含n个方法的对象或函数
}
 
 <body>
 <script type="text/javascript" src="myModule.js" ><script/>
  <script type="text/javascript">
  var fn=myModule()
  fn.doSomething
  fn.doOtherthing
  //控制台输出
  doSomething() MY ATGUIGU
  soOtherthing() my atguigu
  <script/>
 </body>
 
 

方式2

function (){
//私有
var msg='My atguigu'
funtion doSomething(){
  console.log('doSomething()'+msg.toUpperCase())
  //
 }
 funtion.doOtherthing(){
 console.log('doOtherthing()’+msg.toLowerCase())
 
 }
   window.myModule={
   doSomething: doSomething,
  doOtherthing: doOtherthing
   }
})()


 <body>
 <script type="text/javascript" src="myModule.js" ><script/>
  <script type="text/javascript">
  var fn=myModule()w
  fn.doSomething
  fn.doOtherthing
  //控制台输出
  doSomething() MY ATGUIGU
  soOtherthing() my atguigu
  <script/>
 </body>

闭包的缺点及解决

1.缺点:函数执行完后,函数内部变量没有及时释放,占用内存时间会变长,如果大量占用内存会容易造成内存泄漏。

2.解决: 能不用闭包就不用,用了要及时释放闭包

内存溢出与内存泄漏

内存溢出:当程序运行时所需要的内存超过了剩余的内存时就会抛出内存溢出的错误。 内存泄漏:占用的内存没有及时释放,积累多了就容易造成内存溢出。

常见的内存泄露: 1.意外的全局变量 2.闭包 3.没有及时清理的回调函数或计时器。