首页 > 代码库 > JS闭包,以及适用场景

JS闭包,以及适用场景

闭包的定义

不用解释了,网上到处都是。简单的说:一个定义在函数内部的函数与包含它的外部函数构成了闭包,内部函数可以访问外部函数的变量,这些变量将一直保存在内存中,直到无法再引用这个内部函数

举个例子:

var vvval = 0;
function outerFun(i) {
    var vval = i;
    function innerFun() {
        var val = i;
        console.log("内部变量:"+val);
        console.log("外部变量:"+vval);
        console.log("全局变量:"+vvval);
        val++;
        vval++;
        vvval++;
    }
    return innerFun;
}
var testFun1 = outerFun(10);
testFun1();//内部变量:10 外部变量:10 全局变量:0
testFun1();//内部变量:10 外部变量:11 全局变量:1
var testFun2 = outerFun(20);
testFun2();//内部变量:20 外部变量:20 全局变量:2
testFun2();//内部变量:20 外部变量:21 全局变量:3

结论:
    val是innerFun()的局部变量,每次执行innerFun()都会重新赋值;
    vval是innerFun()的上一级变量,每次执行innerFun()的结果会保存在内存中,是outerFun()的局部变量,每次执行outerFun()都会重新赋值;
    vvval是innerFun()的上上一级变量,每次执行innerFun()的结果会保存在内存中,是outerFun()的上一级变量,每次执行outerFun()的结果会保存在内存中;
    
在JavaScript中,作用域只有全局作用域和函数级作用域两种,在下一级作用域中可以访问和修改上一级作用域的变量,在定义函数时,JS会自动维护一个作用域链,当前的局部作用域位于作用域链顶端,并可以依次向上回溯。闭包的实质就是延长了作用域链。

再举一个例子:

//若已经定义了10个<div>,现在想用循环给每个<div>根据序号绑定不同的事件
var i;
for(i=0;i<10;i++) {
    $("div:eq("+i+")").on("click",function() {
        console.log(i);
    });
}

然而,点击每个<div>输出结果均为10,这是因为i是全局变量,当改变i的值时,所有引用了它的函数都会受到影响。这时我们可以通过延长作用域链,为i的值保存一个副本,使它们之间不会互相影响:

var i;
for(i=0;i<10;i++) {
    function outer() {
        var vval = i;
        function inner() {
            console.log(vval);
        }
        $("div:eq("+vval+")").on("click",inner);
    }
    outer();
}

每循环一次就定义了一个外部函数outer()和一个内部函数inner(),因为inner()被绑定在<div>的click事件上,所以outer()中的变量没有在执行完之后就被释放,而是保存在内存中,最后需要执行一次outer(),初始化变量vval,当然你也可以使用自执行的匿名函数代替outer()。
解释一下:在JS中函数是可以重复定义的,只是执行的是最后一次定义的函数而已,例如:

function a() {
    console.log(1);
}
a();
function a() {
    console.log(2);
}
a();
//输出两个2

 

JS闭包,以及适用场景