一、概念理解
1、闭包概念:有权访问另一个函数作用域中变量的函数。
也就是保存自己私有的变量,通过提供的接口(方法)给外部使用,但外部不能直接访问该变量。
可以简单理解为:一个作用域可以访问另外一个函数内部的局部变量
看上图~可以理解为子函数可以访问到父函数的一个局部变量,而父函数访问不到子函数的变量。
并且所谓闭包~我们的写法不就是函数里面再套个函数嘛~
本质:函数内部和函数外部沟通的桥梁。
一般来说,闭包需要满足三个条件:
【1】访问所在作用域;【2】函数嵌套;【3】在所在作用域外被调用
function dad(){
var num = 10;
function son(){
console.log(num)//可以访问到dad函数的局部变量num
}
son()
}
dad()
在这里我们要更好的理解闭包,还需要简单理解个js垃圾回收机制的知识点~
2、js垃圾回收机制(补充)
简单的说,当一个函数被执行完后,其作用域会被收回,如果形成了闭包,执行完后其作用域就不会被收回。
垃圾回收的核心思路:清理调内存中不在被引用的值。
通俗的讲,就是把内存中没用的值,都清理掉!
那我们怎么判断它就没有用了呢?
①对于局部变量,那么它在函数调用完之后,就没用了(你都调用完啦,那要你有什么用呢!)
②对于全局变量,在浏览器把页面卸载掉的时候消失,都要卸载页面了,这个过程肯定会消耗比较大,所以会按照固定时间,也就是周期性的进行回收。
闭包不能被回收,占用不能被回收。
栈内存 -自动分配内存,页面打开就形成,只有页面关闭才释放。
函数块级私有上下文:
一般代码执行完,就被释放。
如果被上下文以外的占用,不仅这个东西不能释放,私有上下文也不能释放。
堆内存-动态分配内存,主要看是否被占用。
如果没被占用,浏览器在空闲时回收,如果被占用,就无法回收
为减少内存,可以用fn=null 手动清除之前的引用。
javascript 中常见的垃圾回收方式:标记清除(常用)、引用计数两种方式。
简单讲一下引用计数和标记清除:
引用计数:
垃圾回收器定期扫描对象,并计算了每个值被引用的次数(引用一次加1,反之减1)。如果一个对象的引用次数为 0(没有被占用),或对该对象的唯一引用是循环的,那么该对象的内存即可回收。
标记清除:
给存储在内存中的所有变量都加上标记,然后,它会去掉处在环境中的变量 【及被环境中的变量引用的变量(闭包)】。剩下的带有标记的变量被视为准备删除的变量,因为是环境中的变量已经无法访问到这些变量了。
二、闭包的优缺点
1、优点
①可以把局部变量长期驻留在内存中(可以理解为优点②的原因)
②在某些方面提升代码的执行效率 【注意!一旦过头就会转换成缺点】
(举个栗子~假如我在院子里养了一群兔子,我把其中几只放在我家里,这样我喂它们多方便呐~可以提高我的喂养效率,但一旦把兔子过多的放家里养,那岂不是乱套了!占用我的空间,反而会降低我的喂养效率,降低我的性能!)
③可以避免全局变量对命名空间的污染
④可以从一个域中取出原本访问不到的变量去使用
2、缺点
①由于闭包里作用域返回的局部变量资源不会被立即销毁回收,所以可能会占用更多的内存。
②过度使用闭包会导致性能下降,建议在非常有必要的时候才使用闭包
欢迎各位大佬指正,Thanks♪(・ω・)ノ