javascript中的闭包
前几天,校园招聘结束了有一段时间,然后群里放了个前端笔试面试试题集的链接。看完后比较郁闷,有很多东西写的不是很好,有“误人子弟”的嫌疑。。。JK也有吐槽,我偶尔发现个关于“闭包”概念的试题。其实仔细想想,自己对闭包的概念也不是很清楚,所以找了资料查询,比较实际的动手练习了下,对闭包做个总结。
一、闭包的概念
闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
坑爹的官方描述,看了半天没想明白这些术语是具体个什么情况。
找了一圈的资料,总算有通俗易懂的解释。这句话实际上是在说:javascript中所有的function都是一个闭包。但是,我们一般所说的闭包是指嵌套的function产生的闭包。
二、闭包的例子
1 function a() { 2 var i = 0; 3 function b() { console.log(++i); } 4 return b; 5 } 6 var c = a(); 7 c();
上面的代码是一个经典的闭包的例子(我稍微做了下修改,把原来的alert改为了console.log)。
可以看出,a中有一个函数b,b引用了a中的局部变量,同时,a在最后返回了函数b。
a、b、c直接的引用关系:

c=a()执行后c指向了a中的b,b中又引用了a中的i,这样c()执行后会输出++i的值(第一次执行是1)。这实际上就是一个闭包。
函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。
你可以好好体味下下面的这段话:所谓“闭包”,就是在构造函数体(a)内定义另外的函数(b)作为目标对象的方法函数,而这个对象的方法函数(b)反过来引用外层函数(a)体中的临时变量(i)。这使得只要目标对象在生存期内始终能保持其方法,就能间接保持原构造函数体当时用到的临时变量值。尽管最开始的构造函数调用已经结束,临时变量的名称也都消失了,但在目 标对象的方法内却始终能引用到该变量的值,而且该值只能通这种方法来访问。即使再次调用相同的构造函数,但只会生成新对象和方法,新的临时变量只是对应新的值,和上次那次调用的是各自独立的。
提供个对上面这段话进行解释的代码:
1 function a() { 2 var i = 0; 3 function b() { console.log(++i); } 4 return b; 5 } 6 var c = a(); 7 c(); 8 var d = a(); 9 d(); 10 c();
代码的输出结果分别是1 1 2。
三、闭包的作用
在解释闭包的作用前,我们先了解下javascript中的垃圾回收机制GC。
在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第三者所引用,那么这两个互相引用的对象也会被回收。
闭包的作用就是,在a执行完毕返回后,不让垃圾回收机制GC收回a所占用的资源。因为a中的b还被c引用到了。资料都说这种理解太肤浅,我对闭包的印象真是从这样的理解开始的。
另一种比较容易混淆的地方就是,如果a不返回b,就是不要代码中的return b的代码,那么就是另外一种情形了,a和b相互引用并且没有第三者引用他们,那么a()执行完毕后,垃圾回收机制就会回收a和b。输出结果当然也是另外一种情况了,有兴趣你可以单独测试下。
四、闭包的应用场景
好吧,这部分我理解还比较浅,引用别人的解释吧。。。
- 保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
- 在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
- 通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)。
私有属性和方法在Constructor外是无法被访问的。
function Constructor(...) {
var that = this;
var membername = value;
function membername(...) {...}
}
以上3点是闭包最基本的应用场景,很多经典案例都源于此。
五、总结
其实自己过去对闭包的理解完全没有把握到关键点,所以这次通过查找资料,动手实践后突然有了豁然开朗的感觉。我希望这篇文章对你也有帮助。
oh my god!我突然发现自己周报还没写!
浙公网安备 33010602011771号