带你彻底理解闭包

2023-02-05 0 1,011

序言

有关JS中旋量群的认知,坚信许多人都和本栏那样刚开始很是疑惑。旋量群在复试中也是发问率十分高的两个难题,本栏也是在看了许多后辈的该文后,归纳出一点儿他们的认知。历史记录与此,本栏水准十分有限 ,若有严重错误含意,还请表示,团结合作。

旋量群的基本概念及事例导出

对旋量群的涵义在JavaScript高阶面向对象(第3版)中是这种叙述:旋量群是指无权出访另两个表达式返回值中的表达式的表达式。

这儿他们具体来说晓得旋量群有3个优点:

①表达式冗余表达式

②表达式外部能提及表达式外部的模块和表达式

③模块和表达式不能被废弃物拆解监督机制拆解

所以旋量群的促进作用也就很显著了。

1. 能在表达式的外部出访到表达式外部的局部表达式。

2. 让那些表达式仍旧留存在缓存中,不能随著表达式的完结而手动封存。

浅显的讲是表达式a的外部表达式b,被表达式a外部的两个表达式提及的这时候,就建立了两个旋量群。

function a(){ var i=0; function b(){ alert(++i); } return b; } var c = a(); c();//外部的表达式

根据上面的例子他们在衍生两个例子

function a(){ var i=0; function b(){ i++; alert(i); } return b; } var c = a(); c();//?1 c();//?2 c();//?3

正确的答案应该是会依次弹出1,2,3。例子解答:

i是表达式a中的两个表达式,它的值在表达式b中被改变,表达式b每执行一次,i的值就在原来的基础上累加 1 。因此,表达式a中的i表达式会一直留存在缓存中。

当他们需要在模块中定义一些表达式,并希望那些表达式一直留存在缓存中但又不能 “污染” 全局的表达式时,就能用旋量群来定义这个模块。

再来看看两个例子

var num = new Array(); for(var i=0; i<4; i++){///num[i] = 旋量群; //旋量群被调用了4次,就会生成4个独立的表达式 //每个表达式外部有他们能出访的个性化(差异)的信息 num[i] = f1(i); } function f1(n){ function f2(){ alert(n); } return f2; } num[2](); num[1](); num[0](); num[3]();

答案为2,1,0,3(这个这时候你了解清楚旋量群之后,这个答案应该是随口而出)

综上事例:

所以他们从中就能发现旋量群的用处

两个是它能读取表达式外部的表达式,另两个是让那些表达式的值仍旧保持在缓存中。

旋量群的优点:

① 减少全局表达式;

② 减少传递表达式的模块量;

③ 封装;

旋量群的缺点:

① 使用旋量群会占有缓存资源,过多的使用旋量群会导致缓存溢出等

缓存泄漏解决方法

简单的说是把那些不需要的表达式,但是废弃物拆解又收不走的的那些赋值为null,然后让废弃物拆解走;

二、旋量群原理

旋量群的实现原理,其实是利用了返回值链的优点,他们都晓得返回值链是在当前执行环境下出访某个表达式时,如果不存在就一直向外层寻找,最终寻找到最外层也是全局返回值,这种就形成了一个链条。

var age = 18; function cat(){ age++; console.log(age);// cat表达式内输出age,该返回值没有,则向外层寻找,结果找到了,输出[19]; } cat();//19看到这儿,大家都会说这不是最简单的表达式和表达式形式吗?旋量群在哪里?别急,他们接着往下看:

再次调用时,结果会一直增加,也就表达式age的值一直递增。

cat();//20 cat();//21 cat();//22

如果程序还有其他表达式,也需要用到age的值,则会受到影响,而且全局表达式还容易被人修改,比较不安全,这是全局表达式容易污染的原因,所以他们必须解决表达式污染难题,那是把表达式封装到表达式内,让它成为局部表达式。

function person(){ var age = 18; function cat(){ age++; console.log(age); } return cat; } person();// 19 person();// 19

这儿又出现难题了,每次调用表达式person,进入该返回值,表达式age就会重新赋值为18,所以cat的值一直是19;所以需要做一下调整:

var per = person();//per相当于表达式catper();// 19 即cat() 这种每次调用不在经过age的初始值,这种就能一直增加了 per();// 20 per();// 21

三、旋量群的其他用处

for(var i=0;i<5;i++){ setTimeout(function(){ console.log(“i的值”+i) },100) }

按照预期它应该依次输出1 2 3 4 5,而结果它输出了五次5,这是为什么呢?原来由于js是单线程的,所以在执行for循环的这时候定时器setTimeout被安排到任务队列中排队等待执行,而在等待过程中for循环就已经在执行,等到setTimeout能执行的这时候,for循环已经完结,i的值也已经编程5,所以打印出来五个5,(如果把for循环里面的var变成let,也能实现预期结果)

修改后使用旋量群

for(var i=0;i<5;i++){ (function(i){ setTimeout(function(){ console.log(“i的值”+i) },100) })(i) }

引入旋量群来留存表达式i,将setTimeout放入立即执行表达式中,将for循环中的循环值i作为模块传递,100毫秒后同时打印出1 2 3 4 5,

那如果他们想实现每隔100毫秒分别依次输出数字,又该怎么改呢?

for(var i=0;i<5;i++){ (function(i){ setTimeout(function(){ console.log(“i的值”+i) },i*100) })(i) }

在这段代码中,相当于同时启动3个定时器,i*100是为4个定时器分别设置了不同的时间,同时启动,但是执行时间不同,每个定时器间隔都是100毫秒,实现了每隔100毫秒就执行一次打印的效果

更新

最近无意中要看到了有人旋量群还能这种定义:

当两个外部表达式被其外部表达式之外的表达式提及时,就形成了两个旋量群。

万变不离其宗,具体看他们怎么认知

根据这个定义他们再来研究研究,先写两个简单的例子:

function A(){ var count = 0; function B(){ count ++; console.log(Hello Word!); } return B; } var C = A(); C(); //输出 Hello Word!

上面代码翻译成自然语言如下:

定义普通表达式 A在 A 中定义普通表达式 B在 A 中返回 B执行 A,并把 A 的返回结果赋值给表达式 C执行 C

把这5步操作归纳成一句话是:

表达式A的外部表达式B被表达式A外的两个表达式 c 提及。

把这句话再加工一下就变成了旋量群的定义:

当两个外部表达式被其外部表达式之外的表达式提及时,就形成了两个旋量群。

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务