一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
回顾
如果知道这块内容的可以跳过这块;
形象的总结一下闭包:
- 外层函数是妈妈;
- 内层函数是宝宝;
- 被外层函数包裹内层函数调用的被保护的局部变量是妈妈给宝宝发的专属红包;
- 掉用外层函数妈妈,生了宝宝,宝宝拿着妈妈给的属于自己的红包,自立门户(宝宝跟妈妈没有关系了);
上图:到底什么是闭包?
- 闭包也是一个对象;
- 闭包就是每次调用外层函数时,临时创建的函数作用域对象;
- 为什么外层函数作用域能够留下来?因为被内层函数作用域链引用着,无法释放;
一句话概括:闭包如何形成? 外层函数调用后,外层函数的作用域对象被内层函数的作用域链引用着,无法释放,就形成了闭包对象;如果小伙伴想更清楚的了解闭包,可以看我上篇文章妈妈再也不担心我面试被问到闭包了(上)
闭包(下)
闭包的缺点
闭包的形成是因为外层函数作用域对象被内层函数作用域链引用着无法释放才形成的闭包,那么问题来了,外层的函数作用域对象无法释放不会有问题吗?
有问题,会造成内存泄漏
闭包缺点:
由于闭包藏的很深,几乎找不到,所以极容易造成内存泄漏
解决
及时释放不用的闭包
如何?
如何释放不用的闭包对象?
将保存内层函数对象的变量赋值为null,导致函数名变量与内层函数对象分开
内层函数被pay变量接住了,但是现在把pay变量设置为null,那么它们之间线就断了,此时内层函数对象成了没人要的宝宝,最后会被js引擎自动释放,内层函数引用的闭包对象也没人要了,闭包对象也会被释放,这样就解决了闭包造成的内存泄漏的问题。
最后内存恢复成最初始的干净状态。
闭包的答题技巧(法则)
找对3种东西:
- 外层函数-妈妈;
- 内层函数(多个)-孩子们;
- 被保护的变量外层函数的局部变量-红包;
外层函数返回内层函数的方法:(3种) - return;
- 强行赋值为全局变量;
- 将函数包裹在对象或者数组种返回;
闭包法则分两种情况: - 妈妈一次生多个孩子:多个孩子共用一个红包;
- 妈妈反复生多个孩子:多次出生的孩子,拥有各自独立的红包,互不影响;
耳听为虚,眼见为实,举几个栗子,我们用法则对号入座一下,看是否有用?
function fun (){
var i=999;
nAdd=function(){
i++
}
return function(){
console.log(i);
}
}
var getN=fun();
getN();
nAdd();
getN();
大家可以试着看看这个输出的值是多少?
我先分析一波,这个可以用闭包法则的第一条:妈妈一次生多个孩子:多个孩子共用一个红包 ;
外层函数fun是妈妈,外层函数的局部变量i是红包,变量nAdd是一个全局的变量,因为给未声明的变量赋值,此变量默认被生成全局变量,根据上面说的外层函数返回内层函数方法,属于第一种,因此,nAdd是个内层函数,下面的return函数自然不用说了,符合返回内层函数方法的第一条,这个函数也属于内层函数,有因内层函数=孩子,因此,外层函数妈妈fun里面包裹了2个内层函数,证明,妈妈一次性生了两个孩子,其中nAdd属于剖腹产,returrn函数属于顺产。
现在明了了,妈妈,红包,孩子都找到了,并且知道妈妈一次生了2个孩子,第一次调用getN函数时,临时创建一个函数作用域对象,那么可以使用闭包法则,属于第一条:妈妈一次生多个孩子:多个孩子共用一个红包; 执行内层函数,红包i目前值是999.所以打印值应该是999,第一次的getN调用完后,释放getN的函数作用域对象;
执行nAdd时,为什么可以找到宝宝内部的函数,上面已经说过了呦,默认成了全局变量了,此时nAdd执行时,会临时创建一个函数作用域并且对象执行完毕也会释放的,根据程序,红包i被赋值成了1000;
第二次执行getN时,重新创建一个函数作用域对象,因为红包共享,上面程序红包i已经被修改成1000,因此这里打印的值为1000,同样的第二次的getN函数执行完毕,释放它自己的函数作用域对象;
这个栗子,是妈妈一次性生了2孩子,两个孩子共用一个红包;
好了,我们看下结果,是否正确?
跟我们分析的结果一样;
再来看波代码里的解析:
再举个栗子:
function mother (){
var i=0;
return function(){
i++;
console.log(i);
}
}
var get1=mother();
get1();
var get2=mother();
get2();
get1();
get2();
同样的大家试着看看输出的值是什么,可以结合我上面的法则哦。
等。。。
开始啦,分析一波,可以告诉你们的是用的是第二条法则哦,妈妈反复生多个孩子:多次出生的孩子,拥有各自独立的红包,互不影响 ,你们用对了吗?
来来来:根据程序,先是创建了一个函数new Function();再者把外层函数妈妈赋值给了全局变量get1,调用外层函数mother,依旧是遵循执行函数的做菜三部曲,在第二步的时候,我们可以看到i是个外层函数的局部变量,那就是红包喽,return一个函数,遵循返回内层函数第一种方法,因此,这就是闭包里面的内层函数了,只有一个内层函数,所以可以肯定的是妈妈一次只生一个孩子,并且妈妈给孩子的红包是i;
执行get1,依旧是执行函数的做菜三部曲,不清楚的,去看我的作用域那篇文章哦,这时i的值被赋值为1;因此此处打印的值为1;
继续执行代码,mother被赋值给全局变量get2;执行get2,三部曲,注意这里重新调用了mother,就会重新创建一个函数作用域,上面那个已经被销毁了,这个是崭新的,它们是互不影响的,那就是妈妈又生了一次孩子,又封一个值为0的红包。最后值为1;
继续执行get1,继续使用第一次妈妈封的红包的值,所以现在值为2;而再执行get2时,它继续使用妈妈第二次封的红包的值也就是第二次闭包里面的值,此时值为2;
这个栗子就是:妈妈反复生了好几次孩子,多次出生的孩子拥有的红包是各自独立的,互不影响;
哦了,分析完毕;看结果:
有图有真相;再看一次代码分析
再来一个栗子:
结言
怎么样?知道法则的你们,对于这些复杂的题也能轻松应对呢?我想是有帮助的趴