1、什么是闭包?
《javascript高级程序设计》的解释:有权访问另一个函数作用域中的变量函数。还有有一种解释是:一个函数访问了它的外部变量,那么它就是一个闭包。
我的理解是,闭包是一个能够通过访问外部变量使我们跨越作用域限制访问其变量的函数,它像一个函数的API接口,或一座桥梁。
为了理清楚自己的思路,所以我们从简单的概念一步一步开始。
2、垃圾回收机制
看代码图:
function fn(){
var a = 1;
}
fn()
console.log(a); //报错
我们都知道,console.log(a)会进行报错,因为在函数作用域外是无法访问到函数内的变量的。为什么呢?因为在js中存在一个垃圾回收机制。借鉴Javascript高级程序设计中的解释来说明什么是垃圾回收机制。
1、标记清除:标记清除属于主动清除,最常见一种方式,很多浏览器都采用这么一种方式。
当变量进入环境(例如:函数中声明的一个变量)时,就将这个变量标记为“进入环境”。从逻辑上说,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则会被标记为离开环境。
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,再去掉环境中变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后垃圾收集器完成内存清除工作,销毁那些带标记的值并回收她们所占用的内存空间。
2、引用计数:被动清除。这是一种不太常见的垃圾收集策略。如果想了解的伙伴们,可自行翻译《Javascript高级程序设计》。
所以也就是说,当函数执行完毕之后,函数内的变量是会被回收的,内存会被清除。
3、闭包实例
var b = 0;
function fn () {
var a = 10;
return function (){
b += 1;
a += 1;
console.log(a)
}
}
var closure = fn();
closure() // 11
closure() // 12
这是一个简单的闭包实例,其中closure(即被return出来的函数)就是闭包函数。
可以看到,closure被运行两次,a的值分别为11和12。这说明什么?说明当a=11的时候,离开fn()时,并没有把a的值给销毁掉。a依然保存在内存中,可如果按照上面所说,当fn()执行完毕之后,垃圾回收机制会自动销毁环境内变量,为什么fn()执行完毕后,a还会依然存在呢?
因为当fn()之后返回了一个函数,这个函数也创建了一个新的作用域。而这个也刚好引用了fn中的变量a,所以a不能够回收,回收就无法引用了。接着再通过调用被return的函数,来修改a的值。但是,一旦闭包closure函数执行结束,也会进行回收。
所以,我们经常可以看到闭包的两个特点:
1、闭包能够使值一直保存在内存中;
2、能够访问到某个函数内的变量。
同时因为这些原因的存在,闭包还存在弊端:容易造成内存泄漏,内存占用也会降低性能。
花了一下午浏览了一些资料,看了很多大神的博客的思路写出来的一篇学习笔记,若是理解有误,或哪里不清晰,望提点。谢谢!
网友评论