JavaScript 闭包初步

来源:互联网 发布:erp企业管理系统源码 编辑:程序博客网 时间:2024/06/14 13:10

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 部分内容做了修改,特此说明。

0 0
原创粉丝点击