JS小镇之闭包工作单
简介:
第一章 JS小镇的年轻人
在一片神秘的大陆之上,有这样一个小镇,说是小镇,不如叫做工厂,因为那里四处只有机器的轰鸣,阴暗的天气时刻笼罩着这里,里面的只有工作人员,夜以继日的进行着他们已经被赋予的工作,一切看起来好像毫无生气一般。
在这小镇上,有着这样两个年轻人,头一个叫小域,因为头脑聪明,精明能干,所以,他在这个工厂负责监视着这里的每一个工作流程,除了限制工作部件的工作方式,他还做着一项看起来很多余的工作,那就是在每一个工作部件进入他的工作环境的时候,将工作部件贴上一个标签,上面写着“正在使用”的字样,等着这个工作部件完成之后,他将标签撕下来,翻转过来,上面写着“可以清理”的字样。
小域这么做也不是没有道理的,这就要说到他的那个朋友小回,这两个人关系很好,而小回并没有小域那么聪明,做不了很多精明的工作,见到他的人,也只会夸他一句“天真”。虽然天真无罪,但是,如果他在这个小镇上他一直没有他的工作,那么他可能就会被驱逐出这个小镇,这是这里的法则,很残酷,但是很现实。
小域为了能够保住小回,于是,想到了自己身边需要一个帮手,那就是用来将那些不用的工作部件,拉出去销毁掉,毕竟自己的工作环境也就那么大,只进不出的话,即便再大的地方,也会有撑满的那一天,可是,要在短短的时间里,让小回认出那大片各式各样的工作部件,并且理清哪些可以用,哪些已经失去了作用,十分的不现实。
在小回正式上岗之后,小域便告诉了小回:“当你看到有 【正在使用】 的字样时,哪些部件就放在那里,不要乱动,然后呢,如果是【可以清理】的字样呢,你就把它装到你的车子上,一并拉出去,倒掉。你自己核算好,每隔一段时间就来一趟,听明白了么?”
小回带着十分天真的语气回答道:“yes,sir~”
js回收机制(标记法):当变量进入执行环境的时候,系统会对当前变量进行一个“进入环境”的标记,如一个函数执行时,便是进了函数的执行环境,此时系统会对函数内部所定义的变量进行标记,因为他们占用了内存空间。当这个函数执行完毕,变量离开环境的时候,那些所有用不到的变量,将会被标记为“离开环境”。
每隔一段时间,系统将会启动回收机制,将标记为离开环境的变量等从内存中清除出去。
第二章 小镇工作
小域的工作很复杂,他独自一人监控着整片区域的工作部件,也就是说,如果有任何纰漏,这里的整片区域可能处在混乱的状态之下,无法正常的工作,他的岗位能够胜任的人并不多,虽然不可替代,但是他也需要付出十分的精力来对待这份工作。每天的遇到的工作都不一样,在小域看来,还是充满乐趣的,毕竟,每天收到的工作单都不一样,像是一道道谜题一般,当你从中走出来的时候,会获得一种莫名的轻松感和愉悦感。
这天,小回来到小域这里,环顾了一圈,周围满满的工作部件,可上面贴的全都是“正在使用”的标签,没有一个是需要自己清理的,于是小回来到了小域身边,看小域也没有那么忙,于是问道:“今儿怎么满满的零件,平时都不少要清理的呀,好像不是你的风格呀?”
小域摆出一份无奈的样子:“这也不能怪我,咱们这里的单子都是外面来的,我只是按照单子上写的代码来工作罢了,今儿写代码的这个人怕是水平不行,怕是不知道我这里会满满当当的,哎,你看着工作部件上的名字,从‘a1’到‘a17’,生怕别人认出来这是干嘛似的,不仅如此,还全都放在最外面,也不知道找个箱子封装一下,除非这个工作区域被关闭,这些东西就都得堆这儿谁知道他一会用什么呢”。
小回仿佛恍然大悟道:“哦~怪不得你经常将一整个箱子里面的东西都给我倒出来,就留个箱子,不过放在外面有啥用啊?”
小域看也没啥其他的事,便耐心的给小回解释起来:“你看哈,你要是弄个箱子呢,需要的时候直接指定哪个箱子,我直接把箱子搬来用,箱子写明需要的部件,当你需要的时候,就告诉我用哪个箱子就行了,那么我就拿过来用,然后呢,用完了,箱子里面的东西就可以扔掉了,箱子里面的东西就少了,咱就可以把箱子叠起来,这里的工作空间就会变大一点,一是,这里面所有人都可以工作的更舒服,如果这里工作空间都满了,那么再有任何部件也塞不进来了,那还怎么工作?二来,告诉我用那个箱子方便,还是告诉我整个一大串工作流程方便?”
js函数的封装不仅仅可以提高代码的复用率,而且因为作用域的存在,局部作用域内的东西在执行完毕后将会全部销毁掉,根据需求,用于节省空间,再次调用将会重新开辟内存空间,虽然增多了执行流程,但是空间上将会大大缩减, 避免因为内存占满而导致页面崩溃的问题。
小回似懂非懂的眨了眨眼:“好像是指定箱子方便点吧,呀,好乱。”
小域微微一笑,他也不指望小回能听够全部懂,不过,小域秉承着尊重的原则,继续给小回做着科普工作:“你平时扔掉的工作部件呢,其实大部分都是箱子里的东西,箱子外的呢也有,不过少,一方面是写代码的人需要本身这些东西常驻,另一方面他们很多人不知道如何清理空间,要么就是懒,明明就是把不用的工作部件换成‘null’型部件就可以了,可惜,很少有人这么干。”
js中,如果有些变量不需要了,可以将该变量设为null,如一些完全失去作用的但是含有大量数据的对象,只需要将其设为null值,垃圾回收器将会因为他们被解除引用,将在内存所占用的部分清理掉。
“哦,好的吧~”小回也不知道懂了没,眼神似乎有些呆滞,陷入了思考一般。
小域也不好多说什么了,这些也够小回理解一段时间了,回头继续看向这个空间,等待下一个指令,或者说下一个单子,毕竟自己的职责是要负责这一片运行的正常。
小回看了看四周,这个地方不仅仅只有小域一个人,还有很多人在忙忙碌碌的工作着,而小域此时仿佛很闲的样子,他从来没有跟自己说过他平时的工作是什么,今天难得有时间,便问了起来:“那你在这平时都忙什么呀?你也没跟我说过,就我知道的你也就是帮我贴了贴标签,他们可说你的工作很难的。”
小域看这里一切正常,于是耐心的回答道:“看见那些箱子了么?那些东西才是我的主要工作,我需要保证外面的任何指令不可以随意使用箱子里面的部件,而里面的部件是否要重新生成开辟还是使用外面已有的部件,这很关键,关系到整个工作流程的正常运转,用最少的部件完成这里所需要的工作,节省这里的空间,其实你看,那个箱子里面还套着一个箱子,一样的,大箱子不能使用小箱子里的东西,小箱子可以使用外面的东西。”
“啊?为什么外面不能用里面的,里面却可以用外面的啊?”小回一脸迷茫的问。
小域笑了笑:“乌龟的屁股-规定(龟腚),另外,箱子里面的东西没用的时候,都让你扔了啊。箱子里了小箱子也是一样,小箱子里的东西还没出来呢,你怎么用?”
“那怪我咯?话说,规定可还行?”
“如果大家都遵守一套规则的时候,那么那些写工作单的人就可以用一样的方法来优化他们的单子,至于怎么写又是他们的问题了。”
“那是不是以后闲置的箱子,我差不多都可以帮你收视咯?”
小域琢磨了一下,感觉那里怪怪的,不过还是答应下来:“好像也没什么问题,你到时候还是问问我吧。”
“嗯!”
js中对作用域的规则,最外部为全局作用域,全局的作用域不可访问任何函数内部的变量,其中一个原因,是当函数执行完毕时,因为函数内部的变量所占的内存“可能”会被销毁,所以,不允许外部向内部访问任何变量。
对于局部作用域,如果当前作用域没有该变量,则会向上一层作用域寻找,直到找到变量或者找到全局作用域为止,如果全局作用域还没有,则会抛出错误。
这种链式查找的方式便是作用域链,作用域的产生仅与定义的位置有关,与执行位置无关。
第三章 无法销毁的箱子
时间慢慢流逝,小回每天都会来小域这里将不用的工作部件带走,因为对这里的规则有所了解之后,时不时的也会直接帮小域将刚闲下来的箱子里面的东西一并带走,小域有的时候看见没什么问题,也就没多说什么,便任由他这么做了。
直到有一天,一个工作单子来到小域这里,看似一切正常,而单子上一个名为“jquery”的箱子,在执行时引起了小域的注意,这个箱子之中套了个小箱子,这并没有什么稀奇的,但是,这个小箱子,一行要求在全局中建立部件的动作引起小域的警戒。
按照往常,这个“jquery”的箱子在执行完毕之后,小域要打算将内部的部件给反转标签的时候,他发现,出现了问题,这个小箱子在全局留下了一个名为“$”的部件,而这个部件需要寻找其他执行部件的时候,按照规则,他必须先去套着他的那一层大箱子里面找,如果大箱子里面留下的东西丢了的话,那么他将什么也找不到,运行将会出问题,所以,大箱子里的东西不能都销毁,小域陷入了迷茫和沉思。
此时小回拉着一辆空车回到了小域的工作空间,看着小域面前放在执行区外的箱子,并没有注意到小域的表情,于是走上前说:“老规矩,这里面的东西,我可就帮你带走了哈!”说罢,便要将大箱子里面的东西往自己的车子里倒。
小域立马反应了过来,一把抓住小回的手,一脸凝重的说道:“等会,那边还有别的东西,你先搞那些,我先考虑一下,这个不太一样。”
小回一脸懵逼,便停下了手上的动作,将箱子放回原位,绕过小域,去其他地方收东西去了。
小域不愧是聪明,在理解了这个大箱子的用途之后,大声感叹:“妙啊!妙啊!”
不等小回问,小域直接跑到小回的身边,双手抓着小回的肩膀,兴奋地说道:“来,我给你看个宝贝,啊,不,这个神奇的箱子,真的好玩!”
小回一脸懵逼的被推到了那个箱子面前,小域来到这个箱子身边,压抑了一下自己兴奋地心情,便对小回解释起来:“你看,这个大箱子里面的小箱子,我是不是说过,这里面的东西可以使用大箱子里的东西?”
小回瞪着眼睛,傻傻的点了点头:“啊……”
小域接着说道:“这个小箱子在全局上留了一个小东西,这个小东西,他的大部分需求部件实际上都在这个大箱子里面,当它需要的时候,根据规则,他就要来这个大箱子里面找,看似这个大箱子是要销毁的,但是就因为这个需求,所以,这个大箱子里面的大部分东西都不可以销毁。”
小回还是一脸懵逼:“然后来?那不是占用了你的空间吗?你兴奋什么啊?”
小域哈哈一笑:“这你就不懂了,这个的好处是,在这个箱子里的任何部件和全局上完全不相干了,也就是说,箱子里面的部件可以随便的命名,然后并不影响全局,如果全局上的变量多了以后,假设我又想使用一个部件,但是不小心跟另一个起了同一个名字,那么到时候我是用原来的还是用新的呢?”
小回呆呆的问道:“就……为了能够不影响起名?”
小域嘴角一翘:“对,这样这个箱子可以自由的放在任何一个地方,只要他们注意不使用这唯一的小部件的名字‘$’就可以了,即完成了他需要大量命令的需求,也不影响其他人的需求,这样的箱子可是妙呀!”
小回好似恍然大悟:“原来如此,那这箱子里面部件全都留下了呗?”
小域带着自信的微笑:“不,有些可以拿走,他们本身就不需要留下,他们只是为了产生其他部件所留下的辅助物品罢了,你下一趟来,我给你标好了,你带走。”
说罢,小域痴迷的陷入了这个箱子的内部结构之中,小回皱了皱眉,心说:“我还是不要听他说什么了,头大……”转身,继续他的工作去了。
js闭包:因为作用域机制的问题, 如果一个函数里面返回了一个函数,其中子函数中又调用了父函数中的某个变量,那么根据规则,返回的子函数所使用的变量应当根据作用域链,根据定义的位置,向上查找变量,而就是这样一个动作,该变量因为没有办法解除引用,所以他并不会被销毁掉,停留在了内存之中。
优点:闭包可以让自己所需要的变量不污染全局变量环境,但是可以像全局变量一样,留下来进行计算等操作。
缺点:滥用闭包,可能会让本来需要清除的变量,强行的留在了内存之中,造成内存泄漏。
终章 代码示例
var a = 100;
function first(){
var a = 1;
return function(){
console.log(a++);
}
}
var second = first();
second(); // 1
second(); // 2
second(); // 3
console.log(a); // 100
以上就是最简单的闭包写法,可以看到,因为作用域链,所使用的变量为first函数内部定义的变量,因为无法销毁,所以,每一次调用,a的值都会改变,但是最后我们在全局上依旧可以定义一个变量a,而且与闭包内部的值互不相干,这种写法,在插件中尤为常见,插件内部的任何东西对我们写的任何变量将没有丝毫影响,其实还有很多其他的写法,不一一列举了,又要解释很久,所以……
综上,这就是隐藏在浏览器中的JS小镇世界的小小一角。
封面结尾:
,大神啊,厉害啊,教教我呗