垃圾回收器
我个人把闭包抽象的称之为”阻止垃圾回收器的函数”或者”有权访问另一个函数内部变量的函数"(当然这个是我个人的理解方式,每个人可能会有不同的理解方式),为什么这样说?这样说还得说说垃圾回收器,一些编程语言如C语言对于内存管理是由程序员说了算,也就是说程序员决定这个变量是否还需要,如果不需要就释放这个变量占用的空间,而这个变量也不复存在了,这样做的好处是可以及时释放内存空间,让那些需要使用内存空间的程序来使用。
而在Javascript中,我们是不需要这样做的,Javascript有一个叫”垃圾回收器”的系统,它会自动对于那些我们不再使用的变量进行回收。那问题来了,它怎么知道我们不再需要这个变量了?在Javascript里面把实现垃圾回收的机制叫”引用计数”(当然在这之前还有一个已经被抛弃的”标记清除”,在这里就不管它了,只关注当前的东西),垃圾回收器会根据代码里面对变量的调用(引用)来判断,如果这个变量的引用计数为0那么就表示可以回收了。
引用计数是如何工作?拿一个例子来说吧:
“有一家公司的小明,他工作是和销售有关的,所以他每天会开公司的车去见客户、接客户进行推销。而取得公车的步骤需要向管车的王大爷进行预约,然后王大爷会把预约纪录到今天的预约表上,使用完后需要把车交给王大爷并把记录划掉。有一天小明需要使用公车,小明打电话给王大爷表明他下午两点会使用公车,王大爷随后把此次预约纪录到了今天的预约表上,到了约定时间,小明取到了公车。随后与客户一番见面商谈过后把公车交还给王大爷,王大爷同时也把预约表上的小明这一条记录给划掉,王大爷随后看了看预约表,今天没有人预约了,看来可以早点下班了,于是把车停回车库下班了。”
其实上面的例子可以看出来,王大爷相当于”垃圾回收器”,而王大爷依据什么来进行处理回收的?是根据预约表,而这个预约表就相当于”引用计数”,当这个预约表上没有人预约公车的时候,王大爷就把车停回了车库,当然如果还有预约王大爷还得一直等待预约表上没有任何预约了才能把车停回车库并下班。也就相当于当这个变量没有人在需要使用的时候,这个变量就可以被“回收”了。
什么是闭包?
在正常的回收机制下,当我们不再使用这个函数或者变量的时候就会被回收,不再使用是指在当前我们执行的状态之后没有出现在调用(引用)此函数或者变量的语句了,比如说函数,执行完过后如果没有再调用就会回收。下面有一个例子,简单的介绍了一下闭包,例子中logHello被赋值一个自执行匿名函数返回的函数,这个函数是有权限访问自执行匿名函数内部的log_num变量的,这样的函数被称为闭包,因为返回的函数内部有一个对自执行匿名函数内部log_num变量的引用。
1 var logHello; 2 3 4 logHello = ( function () { 5 6 var log_num = 20; 7 8 return function() { 9 10 return log_num; 11 12 }; 13 14 } )();
下面还有一个例子,logHello被赋值自执行函数返回的一个对象,这个对象里面包含了两个方法”read”和”write”,这两个方法都属于闭包,他们都有权访问log_name变量。”read”负责读取log_name这个变量的值,而”write”负责重写log_name的值,在外部是没有任何情况直接访问log_name变量的,只能通过这两个方法来进行间接的访问和设置这个变量,这样的方法同样属于闭包。
1 var logHello; 2 3 logHello = ( function () { 4 5 var log_name = ‘wyz‘; 6 7 return { 8 read: function () { 9 return log_name; 10 }, 11 12 write: function (newValue) { 13 log_name = newValue; 14 } 15 }; 16 17 } )();
闭包是怎么形成的?
从上面都知道判断一个变量是否可以回收,根据这个变量的引用计数就可以判断,比如下面例中,局部变量log_name的引用计数为1,表示有一个引用,所以就垃圾回收器就不会回收此变量,这就是闭包的形成。
1 var logHello; 2 3 logHello = ( function () { 4 5 6 var log_num = 20; 7 8 return function() { 9 10 return log_num; <<返回一个匿名函数,函数内部可以对局部变量log_num进行访问。 11 12 }; 13 14 15 } )();
经过上面的一些例子,就很容易理解了,噢~还没有理解?,那你再继续看看后面的总结吧(但相信我,多思考思考,肯定能理解)。
关于闭包,总结一下,可以说成有权限访问另外一个函数内部变量的函数并且函数不会随着执行完毕而被回收,因为在返回的闭包函数中会存在着对这个函数内部变量的引用。