十三、初了解JS闭包问题

一、全局变量、局部变量

1. JS中变量按作用域可分为全局和局部变量,全局变量是作用于整个JS程序中的,局部变量可以理解为私有变量,即一个函数内部定义的变量,只供这个函数内部使用,对于其他函数或脚本代码是不可用的。全局和局部变量即便是名称相同,也是两个不同的变量,修改其中一个不会影响到另一个的值;

注意:在定义变量声明时需要使用到关键字var,但是也可以将其省略,不使用var关键字的变量无论是在函数内部还是外部都是一个全局变量。

 

二、JS闭包

1.JS闭包是指可访问上一层函数作用域里的变量的函数,即便上一层函数已经关闭;

  其实可以这样理解JS的闭包就是指让此函数可以使用其他函数内部定义的局部变量

例如:

function a(){

  var i=10; //定义局部变量

  function  c(){  //嵌套函数

  i++;

return i;

}

return c();

}

var fun=a();  //将函数赋给变量fun

console.log(fun);  //console.log(); 控制台输出

 

这个例子是让控制台输出变量fun,即函数a(),a()函数返回函数c(),所以执行函数c(),这里就发生了JS闭包,即访问上一层函数作用域里的变量的函数,所以c()函数返回的i11,即最终控制台输出11

 

2.JS闭包的内存泄漏及占用不必要内存缺点

1) 内存溢出:指程序向系统申请的一定大小的内存,但是系统无法满足程序所需而造成的内存溢出;

   内存泄漏:是指程序所申请的内存一直得不到释放,即未被GC回收;就是说在一般项目中,声明的变量被一直保存在内存中,但是这个变量使用完成后GC无法回收这个变量占用的内存给别的程序使用就称为内存泄漏;

/****************************************************************/

插入一点GC(garbage collection)概念:js垃圾回收机制

JavaScript引擎基础GC方案是:mark and sweep(标记清除),即:

遍历所有可访问的对象;

回收已不可访问的对象;

GC时,为安全考虑,停止响应其他操作。JsGC100ms甚至以上,对一般应用还好,但对于js游戏,动画对连贯性要求比较高的应用,则需要优化,避免GC造成长时间停止响应;

/****************************************************************/

2)由于闭包会使变量始终保持在内存中,这样若形成内存泄漏的堆积会导致消耗尽系统的内存,所以尽量避免不必要的闭包使用;

需注意的是:闭包并不会造成内存泄漏,内存泄漏是浏览器的bug;

 

例如:

function p1(){

var a=1;

b=function(){  //b不仅是一个全局变量,而且b的值是一个匿名函数本身是一个闭包

a+=1;

}

function p2(){

Console.log(a);

}

return p2;

}

var result=p1();

result();  //这里p1()返回的是p2,所以result()就相当于闭包p2()函数,p2()运行第一次

b();

result();  //p2()运行第二次

 

第一次运行结果是1 第二次经过b()函数加1,结果是2证明了函数p1中的局部变量a一直保存在内存中,并没有在p1调用后被自动清除;p1p2的父函数,而p2被赋给了一个全局变量,p2的存在依赖于p1,p2始终存在于内存中,不会在调用结束后被GC回收;

 

3.闭包内存泄漏的解决办法:在退出函数之前,将不使用的局部变量全部删除;

 

4.在一个作用域定义2个闭包,这两个闭包会共享同样的私有变量:

例如:

function sum(){

var a=[];

for(var i=0;i<10;i++){

a[i]=function(){  //匿名函数 闭包 ia[]角标

return i;

}

}

return a;   //这里返回的a数组

}

var a=sum();

console.log(a[5]());

输出结果为10

代码中第一个陷阱是定义的变量a和函数内部数组a名称一致,需要注意,另外,闭包的匿名函数被嵌套在一个for循环里,相当于创建了10个闭包,并且这10个闭包被存储到一个数组中,又由于这些数组都是在同一个函数中被定义,所以共享变量i;所以sum()返回时,变量i的值是10,所有闭包都共享了这一值;

 

修改一下:

function sum(b){

return function(){

  return b;

}

}

var a=[];

for(var i=0;i<10;i++){

a[i]=sum(i);

}

console.log(a[5]());

输出结果为5

 

5.闭包面试题举例

function fun(n,o) {

  console.log(o)

  return: {  //返回对象

    fun:function(m){

      return fun(m,n); //返回最外层fun(n,o)

    }

  };

}

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

var b = fun(0).fun(1).fun(2).fun(3);  

var c = fun(0).fun(1);  c.fun(2);  c.fun(3);  

:三行a,b,c的输出分别是什么?

第一行undefined,0,0,0

解析:a=fun(0) 传入实参n=0,o未定义,故输出的为undefined

          a.fun(1) fun(n,o)返回的对象fun(m),m=1,所以return fun(1,0) ,这时o=0,故输出的为0;

  a.fun(2) 对象还是a 所以同理m=2,return fun(2,0)输出结果为0

  a.fun(3)同理,输出0

 

第二行undefined,0,1,2

解析:第一个b=fun(0)a=fun(0)输出undefined

          b=fun(0).fun(1)a.fun(1)输出0

b=fun(0).fun(1).fun(2) 由上一步知return fun(1,0),所以fun(2)是指对象fun(m)m=2,这样return fun(2,1),所以输出为1

b = fun(0).fun(1).fun(2).fun(3)同理向下推输出为2

 

第三行 undefined,0,1,1

解析:c=fun(0).fun(1)b=fun(0).fun(1)输出undefined,0

  c.fun(2)b=fun(0).fun(1).fun(2)输出1

  c.fun(3)这里对象还是c故输出还是1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值