手记

Javascript 闭包

1.理解闭包

    1.1 如何产生闭包?

        当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时,就产生了闭包

    1.2 闭包到底是什么?

        i:闭包是嵌套的内部函数

        ii:包含被引用变量(函数)的对象

        iii:闭包存在于嵌套的内部函数中

    1.3 产生闭包的条件:

        i:嵌套的函数

        ii:内部函数引用了外部函数的数据(变量/函数)

 function foo(){    
   var a = 1;    
   function bar(){
     //内部函数bar引用了外部函数foo的a变量,此时产生闭包   
     console.log(a);    
   }
   bar()  
 }  
 foo();

2.常见的闭包

    2.1 将函数作为另一个函数的返回值

function fn1(){  
  var a = 1;  
  function fn2(){    
    a++;    
    console.log(a);  
  }  
  return fn2
}
var fn = fn1();//产生闭包,变量a = 1
fn() //2
fn() //3

    2.2 将函数作为实参传递给另一个函数调用

function delay(msg, time){  
  setTimeout(function(){    
    alert(msg)  
  }, time)
}
delay('Hello Closure', 1000)

3.闭包的作用

    3.1 使用函数内部的变量在函数执行完后,仍然存活在内存中(延长了局部变量的生命周期)

    3.2 让函数外部可以操作(读/写)到函数内部的数据(变量/函数)

4.闭包的生命周期

    4.1 产生:在嵌套的内部函数定义执行完成时就产生了(不是在调用)

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

function foo(){  
  //此时闭包已经产生(函数提升,内部函数已经创建)    
  var a = 1;    
  function bar(){      
    console.log(a);    
  }    
  return bar;  
}
var f = foo();
f()
f = null //闭包死亡(包含闭包的函数成为垃圾对象)

5.闭包的使用:自定义JS模块

(function (window){  
  //私有数据  
  var msg = "Hello closure";  
  function doSomething() {    
    console.log("doSomething() "+msg.toUpperCase());  
  }  
  function doOtherthing() {    
    console.log("doOtherthing() "+msg.toLowerCase());  
  }  
  //向外暴露对象  
  window.module = {    
    doSomething:doSomething,    
    doOtherthing:doOtherthing  
  }
})(window)
module.doSomething(); //doSomething() HELLO CLOSURE
module.doOtherthing(); //doOtherthing() hello closure

6.闭包的缺点及解决

    6.1 缺点:

        i:函数执行完后,函数内的局部变量没有释放,占用内存时间会变长

        ii:容易造成内存泄漏

    6.2 解决:

        i:能不用闭包就不用

        ii:及时释放

function fn1() {  
  var ary = new Array(100000);  
  function  fn2() {    
   console.log(ary)  
  }  
  return fn2;
}
var fn = fn1()
fn()
fn = null; //让内部函数成为垃圾对象-->回收闭包

补充知识点:

    1.内存溢出

        i:一种程序运行出现的错误

        ii:当程序运行需要的内存超过了剩余内存时,就抛出内存溢出的错误

    2.内存泄漏

        i:占用的内存没有及时释放

        ii:内存泄漏积累多了,容易导致内存溢出

        iii:常见的内存泄漏:意外的全局变量,没有及时清理的定时器或者回调函数,闭包

//内存溢出
var obj = {};
for(var i = 0; i < 10000; i++){  
  obj[i] = new Array(1000000)
}
//浏览器报错:显示此网页时内存不足
//内存泄漏
//意外的全局变量
function fn() {  
  ary = new Array(100000)  
  console.log(ary)
}
fn()

//没有及时清理的定时器或者回调函数
var intervalId = setInterval(function() {  
  console.log("hello closure")
}, 1000)
clearInterval(intervalId) //清除定时器

//闭包
function fn1() {  
  var ary = new Array(100000);  
  function fn2() {    
    console.log(ary)  
  }  
  return fn2;
}
var fn = fn1()
fn()

 面试题1

//code1 
var name = "outside" 
var obj = {   
  name:"inside",   
  getNameFunc:function(){     
    return function(){       
      return this.name     
    }
  } 
} 
alert(obj.getNameFunc()()) //? 是否有闭包? 

//code2 
var name = "outside" 
  var obj = {   
  name:"inside",   
  getNameFunc:function(){     
    var that = this;     
    return function(){       
      return that.name     
    }   
  } 
} 
alert(obj.getNameFunc()()) //? 是否有闭包

面试题2

function foo(v1, v2){  
  console.log(v2);  
  return {    
    foo:function(v3){      
      return foo(v3, v1);    
    }  
  }
}
var a = foo(0); a.foo(1); a.foo(2); a.foo(3) //?
var b = foo(0).foo(1).foo(2).foo(3)//?
var c = foo(0).foo(1); c.foo(2); c.foo(3)//?

PS:面试题答案参考评论区

2人推荐
随时随地看视频
慕课网APP

热门评论

1.var a = foo(0); a.foo(1); a.foo(2); a.foo(3)

var a = foo(0) --> 此时 a 等同于 

{

foo:function(v3){

      return foo(v3, v1);

    }

}

输出undefined

产生闭包,此时闭包里的变量v1等于0

a.foo(1) --> 调用的时foo:function(v3) --> return foo(v3, 0) 

输出 0

由于执行了foo(外部),产生新闭包,但闭包随着foo()调用结束后消失

换个角度理解:

如果 var x = a.foo(1) 则此时产生闭包,闭包里面的变量v3等于1

但是由于 a.foo(1) 没有变量接受,所以闭包随之消失

同理,a.foo(2), a.foo(3) 始终调用的a里面产生的闭包,变量v1 = 0;

所以:a.foo(2), a.foo(3) // 0, 0

所以最终输出:

undefined, 0, 0, 0

2.var b = foo(0).foo(1).foo(2).foo(3)

通过1可知,b = foo(0).foo 此时产生新的闭包,闭包里面的变量为v1 = 0;

同理可得 b = foo(0).foo(1).foo 此时产生新的闭包,闭包里面的变量为v3 = 1

同理可得 b = foo(0).foo(1).foo(2).foo 此时产生新的闭包,闭包里面的变量为v3 = 2

所以最终输出:

undefined, 0, 1, 2


面试题1:

outside,无闭包

inside, 有闭包

面试题2:


查看全部评论