JS闭包的一些重新思考

上网浏览到关于JS闭包的一些知识,突然发现以前对闭包的认知有可能有很大的错误。重新整理思考一下。
(1)什么是闭包?

function outFn(){
    alert("out");
    function inFn(){
        alert("in");
    }
    var b =inFn;
    return b;
}
var a = new outFn();
a();

正常情况下,outFn()的外部是不能访问inFn()的,因为这涉及到一个作用域的问题。但是JS中有一种引用机制,它可以传递函数。所谓传递函数,就是把这个函数的地址赋予一个变量。然后通过这个变量来访问这个函数的地址。

所以,如果内部函数被外部(这里是outFn())的外部(这里是全局)访问了,我们就说这是一个闭包。

有两种传递方式。一种是上面那种,返回一个被赋予inFn()的地址的变量b。通过访问b就可以访问内部函数inFn()了,所以这就是为什么我们需要return b; 的原因。

还有一种方式如下:

var a;
function outFn(){
    function inFn(){
        alert("in");
    }
    a=inFn;
}
outFn();
a();

先定义一个全局变量a,然后在outFn()中把inFn()的地址赋予给a(实际上就是引用),这时变量a的值就被改变了,因为它是全局变量。此时,访问a就相当于访问inFn()了。这种方法有一个地方需要注意 ,那就是必须先调用一次outFn(),不然变量a的值是不会有任何变化的。

我觉得可以通过下面一些实验加强对引用的理解:
(1)

var a=0;
function outFn(){

    function inFn(){
        a++;
        alert(a);
    }
    return inFn;
}
var b = new outFn();
var c = new outFn();
b();
b();
c();
c();
//1 2 3 4 

虽然不断的创建并调用了新的实例b 和 c,但是由于inFn()里面引用的是全局变量a。因此改变的是同一个a(都是这个地址)。所以输出是递增的。
(2)

function outFn(){
    var a=0;
    function inFn(){
        a++;
        alert(a);
    }
    return inFn;
}
var b = new outFn();
var c = new outFn();
b();
b();
c();
c();
//1 2 1 2

由于每次的实例化都会赋予变量一个新的地址,所以b和c的a的地址是不同的。因此这两个实例互不影响。当连续两次调用b()时,由于第一次已经对变量a做出改变,所以第二次访问变量a是访问同一个地址,此时a已经变成1了。因此输出的是2。
(3)

function outFn(){
    function inFn(){
        var a=0;
        a++;
        alert(a);
    }
    return inFn;
}
var b = new outFn();
var c = new outFn();
b();
b();
c();
c();
// 1 1 1 1 

由于这时候变量a在内部函数里面,又因为每次调用outFn()的实例时,都会创建一个新的函数inFn(),所以里面的变量a也是新的。(所谓新的,就是在新的内存地址里面)。因此每次调用输出都是1。

这就引出了闭包的一个问题:内存泄漏。
所谓内存泄漏就是变量的内存得不到回收,增加负荷。由于Javascript的垃圾回收机制是回收那些不再被引用的变量(让这些变量=null)。又因为inFn()一直在被外面的实例调用。所以变量a得不到回收。这样就会造成内存泄漏了。解决方法就是手动让这些变量变成null:

function outFn(){
    function inFn(){
        var a=0;
        a++;
        alert(a);
    }
    return inFn;
    a=null;
}
var b = new outFn();
var c = new outFn();
b();
b();
c();
c();
// 1 1 1 1

闭包的优点:
(1)够安全。因为变量是在函数内部里面的,或者是上一层函数里面,外面没办法随便改变和访问他。
(2)变量不会被销毁。在某些时候确实需要某些变量逃避JS垃圾回收机构的回收。会发现和上面的内存泄漏有所矛盾。所以闭包是一把双刃剑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值