闭包

79 阅读2分钟

当内部函数被返回到外部并被保存时,一定会产生闭包现象,闭包会导致内部函数的作用域链不释放(外部词法环境不随着执行上下文销毁而销毁),过度的闭包可能导致内存泄漏或加载过慢。

比如以下代码,将test2作为返回值赋值给test3,此时test2函数便可以一直钩住test1的词法环境,拿到它环境中的变量、函数。

function test1(){
    function test2(){
        var b = 2;
        console.log(a);
    }
    var a = 1;
    return test2;
}
var test3 = test1();
test3(); // 1

闭包与IIFE

此处内部函数arr[i]并没有执行,闭包现象拿到了i的最终值是10,所以打印出的都是10

function test(){
    var arr = [];
    // 相当于是 var i = 0;
    for(var i = 0; i < 10; i++){
        arr[i] = function(){
            document.write(i + ' ');
        }
    }
    return arr;
}
var myArr = test();

for(var j = 0; j < 10; j++){
    myArr[j]();
}
// 10 10 10 10 10 10 10 10 10 10

此处内部函数是立即执行函数,所以打印出的都是当前循环出的i值。

function test(){
    for(i = 0; i < 10; i++){
        (function(){
            document.write(i + ' ');
        })();
    }
}
test();

此处参与循环的函数是立即执行函数,每次循环时,i值作为实参被保存进了立即执行函数中,之后内部函数调用拿到的i值都是立即执行函数当时保存的i值。

function test(){
    var arr = [];
    for(i = 0; i < 10; i++){
        (function(j){
            arr[j] = function(){
                document.write(j + ' ');
            }
        })(i);
    }
    return arr;
}
var myArr = test();

for(var j = 0; j < 10; j++){
    myArr[j]();
}

闭包实现累加器

// 累加器
function test1(){
    var num = 0;
    function test2(){
        num++;
        console.log(num);
    }
    return test2;
}
var add = test1();
add(); // 1  
add(); // 2
add(); // 3   

闭包实现增删改查

function class1(){
    var name = [];
    var methods = {
        add: function(i){
            name.push(i);
            console.log(name);
        },
        leave: function(j){
            name.splice(j, 1);
            console.log(name);
        }
    }
    return methods;
}
demo = class1();
demo.add("小明");
demo.add("小红");
demo.add("小方");
demo.add("小白");
demo.leave(1);