@linux1s1s
2015-04-26T08:21:39.000000Z
字数 3435
阅读 2267
JavaScript
我们先从一个基本的内部类开始
function outerFn() {document.write("Outer function<br/>");function innerFn() {document.write("Inner function<br/>");}}
假如我们想在outerFn()外调用innerFn()肿么办
function outerFn() {document.write("Outer function<br/>");function innerFn() {document.write("Inner function<br/>");}}innerFn();
上面的代码会出现JavaScript错误,那么该怎么调用呢?
JavaScript允许开发人员像传递任何类型的数据一样传递函数,也就是说,JavaScript中的内部函数能够逃脱定义他们的外部函数。
var globalVar;function outerFn() {document.write("Outer function<br/>");function innerFn() {document.write("Inner function<br/>");}globalVar = innerFn;}outerFn();globalVar();
这种逃逸方式是:内部函数指定给一个全局变量
function outerFn() {document.write("Outer function<br/>");function innerFn() {document.write("Inner function<br/>");}return innerFn;}var fnRef = outerFn();fnRef();
这种逃逸方式是:通过在父函数的返回值来获得内部函数引用。
这种即使离开函数作用域的情况下仍然能够通过引用调用内部函数,意味着只要存在调用内部函数的可能,JavaScript就需要保留被引用的函数。而且JavaScript运行时需要跟踪引用这个内部函数的所有变量,直到最后一个变量废弃,JavaScript的垃圾收集器才能释放相应的内存空间.
闭包是指有权限访问另一个函数作用域的变量的函数
闭包的特性:
function outerFn() {document.write("Outer function<br/>");function innerFn() {var innerVar = 0;innerVar++;document.write("Inner function\t");document.write("innerVar = "+innerVar+"<br/>");}return innerFn;}var fnRef = outerFn();fnRef();fnRef();var fnRef2 = outerFn();fnRef2();fnRef2();
运行结果:
Outer function
Inner function innerVar = 1
Inner function innerVar = 1
Outer function
Inner function innerVar = 1
Inner function innerVar = 1
var globalVar = 0;function outerFn() {document.write("Outer function<br/>");function innerFn() {globalVar++;document.write("Inner function\t");document.write("globalVar = " + globalVar + "<br/>");}return innerFn;}var fnRef = outerFn();fnRef();fnRef();var fnRef2 = outerFn();fnRef2();fnRef2();
运行结果:
Outer function
Inner function globalVar = 1
Inner function globalVar = 2
Outer function
Inner function globalVar = 3
Inner function globalVar = 4
父函数的局部变量被内部类引用(有兴趣可以了解一下作用域链和活动对象的知识)
function outerFn() {var outerVar = 0;document.write("Outer function<br/>");function innerFn() {outerVar++;document.write("Inner function\t");document.write("outerVar = " + outerVar + "<br/>");}return innerFn;}var fnRef = outerFn();fnRef();fnRef();var fnRef2 = outerFn();fnRef2();fnRef2();
这一次结果非常有意思,也许或出乎我们的意料
Outer function
Inner function outerVar = 1
Inner function outerVar = 2
Outer function
Inner function outerVar = 1
Inner function outerVar = 2
我们看到的是前面两种情况合成的效果,通过每个引用调用innerFn都会独立的递增outerVar。也就是说第二次调用outerFn没有继续沿用outerVar的值,而是在第二次函数调用的作用域创建并绑定了一个一个新的outerVar实例,两个计数器完全无关。
function outerFn() {var outerVar = 0;document.write("Outer function<br/>");function innerFn1() {outerVar++;document.write("Inner function 1\t");document.write("outerVar = " + outerVar + "<br/>");}function innerFn2() {outerVar += 2;document.write("Inner function 2\t");document.write("outerVar = " + outerVar + "<br/>");}return { "fn1": innerFn1, "fn2": innerFn2 };}var fnRef = outerFn();fnRef.fn1();fnRef.fn2();fnRef.fn1();var fnRef2 = outerFn();fnRef2.fn1();fnRef2.fn2();fnRef2.fn1();
运行结果:
Outer function
Inner function 1 outerVar = 1
Inner function 2 outerVar = 3
Inner function 1 outerVar = 4
Outer function
Inner function 1 outerVar = 1
Inner function 2 outerVar = 3
Inner function 1 outerVar = 4
innerFn1和innerFn2引用了同一个局部变量,因此他们共享一个封闭环境。当innerFn1为outerVar递增一时,就为innerFn2设置了outerVar的新的起点值,反之亦然。我们也看到对outerFn的后续调用还会创建这些闭包的新实例,同时也会创建新的封闭环境,本质上是创建了一个新对象,自由变量就是这个对象的实例变量,而闭包就是这个对象的实例方法,而且这些变量也是私有的,因为不能在封装它们的作用域外部直接引用这些变量,从而确保了了面向对象数据的专有性。
看完上面的基本知识,你或许对闭包有了一个比较浅显的认识,学过C/C++的同学应该理解起来比较容易,因为闭包特别像是指针函数,但是有不是完全是,因为还有作用域的概念。如果想更深入的认识闭包可以进一步学习JavaScript作用域链和活动对象。
本文转自:http://www.cnblogs.com/dolphinX/archive/2012/09/29/2708763.html 部分内容做了修改,特此说明。
