闭包

224 阅读2分钟
// 一个外部函数里面套一个内部函数,内部函数调用外部函数的局部变量,当外部函数执行完之后,变量不会释放;外部函数和内部函数结束的时间不一样,如果外部函数执行完之后,变量不想被释放,
// 优点,变量不会被释放,
// 缺点:会占据内存,手动释放变量。
//    造成内存泄漏:
// setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
// 闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
// 防止内存泄露:
// 1、不要动态绑定事件;
// 2、不要在动态添加,或者会被动态移除的dom上绑事件,用事件冒泡在父容器监听事件;
// 3、如果要违反上面的原则,必须提供destroy方法,保证移除dom后事件也被移除,这点可以参考Backbone的源代码,做的比较好;
// 4、单例化,少创建dom,少绑事件。
function foo(x) {
    var tmp = 3;
    return function (y) {
        alert(x + y + (++tmp));
    }
}
var bar = foo(2); // bar 现在是一个闭包
bar(10);
//示例
var btnList = document.getElementsByClassName("btn"),
  len = btnList.length;
    for(var i = 0;i<len;i++){
        (function(j){
                btnList[j].onclick = function(){
                console.log("第"+j+"个按钮被点击到了")
            }   
        })(i)
    } 
// for循环每一次都执行一个 IIEF (自执行函数),每一次变量 i 被当做参数传到IIEF中去 , 
// 那么这个自执行函数中创建了一个变量,参数 j 然后元素节点 btnList 绑定一个onclick事件,
// 执行函数里面需要用到这个参数 j ,但是你又没点 ,
// 那么这个遍历 j 就没有被清理 , 就一直在参数里面被保存着 , 
// 每一个IIEF都做一样的事情 , 所以这个时候就产生了闭包 , 变量 j 并没有被回收,依然在等待你使用。
1.
function fn(){
var num = 0;
return function(){
    num+=1;
    console.log(num);&emsp;&emsp;&emsp;
};
}
var f = fn();
f(); //1
f(); //2
2.&emsp;
function fn(){
    var num = 5;
    num+=1;
    alert(num);
 }&emsp;&emsp;
fn(); //6
fn(); //6
3.
function fn(){
    var num = 0;
    return function(){
    num+=1;
    alert(num);&emsp;&emsp;&emsp;
    };&emsp;&emsp;
}
var f = fn();
fn(); //1
fn(); //2