【js的闭包】个人学习闭包的总结

本文深入解析闭包的概念、作用、内存泄露问题及其解决策略,通过实例演示了闭包在累加器和循环中的巧妙应用,助你理解闭包的原理和实战技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录


闭包(面试必问)

闭包的概念

什么是闭包?

  • 闭包就是函数嵌套函数。

为什么要用闭包?

  1. 在外面定义全局变量会造成污染,命名空间冲突。
  2. 主要是为了在函数外面可以访问函数内部的局部变量。
  3. 函数:调用时,开辟空间,调用结束后,立即释放空间

闭包的坏处

大量使用闭包的话,会产生内存泄漏(IE)

如何解决内存泄漏?

  • 将使用完毕的变量赋值为null。

闭包的原理

利用了js的垃圾回收机制,如果在正常情况下,当一个函数调用完就会立即释放空间,包括函数里面声明的变量。但是在回收垃圾的过程中,发现了被回收的这个变量正在被另一个函数使用,那么这个变量将永远不再被回收。

闭包的基本语法

  • 在函数中返回一个匿名函数,匿名函数中返回要返回的变量
  • 使用这个变量的方法:通过匿名函数自运行
  • 闭包返回的是一个函数
function fn(){
        var a = 3;
        return function(){ //闭火罩(闭包函数) 保护变量a 
            return a;  //常驻内存 相当于把var a = 3 变成了全局变量 
        }
    }
    alert(fn()()); //3

闭包的案例

使用全局变量进行累加和

  1. 案例一:
// 使用全局变量进行累加和 这里没有使用闭包
var a = 3;
function fn(){
    return ++ a;
}
fn();
console.log(a);  //4
fn();
console.log(a); //5
fn();
console.log(a); //6
// 分析:调用一次函数,输出次变量,由于函数用没有声明变量,所以会在全局变量中寻找a的值
  1. 案例二:
 //使用局部变量进行累加和 使用闭包的错误方法
function fn(){
    var a = 3;
    return function(){
        return ++ a;
    }
}

console.log(fn()());  //4
/*
    var a = 3;
    function(){ return ++ a}(); //a = 4
*/
console.log(fn()());  //4
/*
    var a = 3;
    function(){ return ++a}; //a = 4
*/
console.log(fn()());  //4
/*
    var a = 3;
    function(){ return ++a}; //a = 4
*/
// 分析:这里用到了闭包,闭包返回一个++a的值,也就是4,因为每次输出都调用了闭包 所以每次去到的值都是4
  1. 案例三:
//使用局部变量进行累加和 闭包的正确使用方法
function fn(){
    var a = 3;
    return function(){
        return ++ a;
    }
}

let fun = fn(); //调用一次fn,返回 function(){}
/*
    var a = 3;
    return function(){return ++ a}()
*/
console.log(fun()); //4
console.log(fun()); //5
console.log(fun()); //6
/*
分析:通过变量fun 接收回来fn的返回值,这个返回值是一个函数,
所以现在fun就是一个函数,这个函数的功能是 返回++a的值,也取到
了变量a的值=3,接下来调用三次fun,结果就是4 5 6 
*/ 

循环里的匿名函数的取值问题

  1. 案例一:
//循环里的匿名函数的取值问题
function fn(){
    var arr = [];
    for(var i = 0;i < 5;i ++){
        arr[i] = i;
    }
    return arr;
}

let list = fn(); //返回arr-数组
for(let i = 0,len = list.length;i < len;i ++){
    console.log(list[i]); //01234
}
/*
    分析:函数fn返回值是数组[0,1,2,3,4]
    把函数的返回值赋值给了变量list 
    遍历数组输出结果
*/ 
  1. 案例二:
//循环里的匿名函数的取值问题
function fn(){
    var arr = [];
    for(var i = 0;i < 5;i ++){
        arr[i] = function(){
            return i;
        };
    }
    return arr;
}

let list = fn(); //返回arr-数组
for(let i = 0,len = list.length;i < len;i ++){
    console.log(list[i]); // 5 * function(){return i;}
}
/*
    分析:函数fn中arr是一个数组,循环添加了函数块,这个函数块没有调用所以就不会执行,只是在声明函数
    函数fn的返回值是这个数组
    变量list拿到了函数fn的返回值 5个函数块
    遍历输出list的没一个函数块,没有调用 结果就是5个函数块
*/ 
  1. 案例三:
//循环里的匿名函数的取值问题
function fn(){
    var arr = [];
    for(var i = 0;i < 5;i ++){
        arr[i] = function(){
            return i;
        };
    }
    return arr;
}
/*
    i = 5;
    arr[0] = function(){return i;}
    arr[1] = function(){return i;}
    arr[2] = function(){return i;}
    arr[3] = function(){return i;}
    arr[4] = function(){return i;}
*/
let list = fn(); //返回arr-数组
for(let i = 0,len = list.length;i < len;i ++){
    console.log(list[i]()); // 55555
}
/*
    分析:函数fn返回了五个函数块 此时i=5退出循环
    五个函数块的功能是返回i
    变量list拿到了这五个函数块 此时fn已经执行完毕 i的值是5(代码是从上到下执行的)
    遍历list依次调用这5个函数块 返回55555
*/ 
  1. 案例4:
function fn(){
    var arr = [];
    for(var i = 0;i < 5;i ++){
        arr[i] = function(){
            return i;
        }();
    }
    return arr;
}

let list = fn(); //返回arr-数组
for(let i = 0,len = list.length;i < len;i ++){
    console.log(list[i]()); // 报错
}
/*
    分析:函数fn中 里层函数自调用 返回值是01234
    此时arr[i]的值并不是函数块
    函数fn把arr反出去,赋值给了list
    下方输出的时候,调用函数,因为list中没有函数,所以报错!
*/ 
  1. 案例5:
//循环里的匿名函数的取值问题
function fn(){
    var arr = [];
    for(var i = 0;i < 5;i ++){
        arr[i] = function(){
            return i;
        }();
    }
    return arr;
}

let list = fn(); //返回arr-数组
for(let i = 0,len = list.length;i < len;i ++){
    console.log(list[i]); // 01234
}
/*
    分析:函数fn中 里层函数自调用 返回值是01234(向父级查找i)
    此时arr[i]的值为0,1,2,3,4
    函数fn把arr反出去,赋值给了list
    下方遍历输出list 结果为0,1,2,3,4
*/
  1. 案例6:
//循环里的匿名函数的取值问题
function fn(){
    var arr = [];
    for(var i = 0;i < 5;i ++){
        arr[i] = function(i){
            return i;
        }();
    }
    return arr;
}

let list = fn(); //返回arr-数组
for(let i = 0,len = list.length;i < len;i ++){
    console.log(list[i]); // 5 * undefined
}
/*
    分析:函数fn中 里层函数有型材 形参是i 
    由于自调用的时候没有传参
    所以返回结果是undefined
    函数fn的返回值是arr 这里赋值给了list
    此时list的值就是五个undefined
    遍历结果,输出5个undefined
*/
  1. 案例7:
//循环里的匿名函数的取值问题
function fn(){
    var arr = [];
    for(var i = 0;i < 5;i ++){
        arr[i] = function(i){
            return function(){
                return i;
            };
        }(i);
    }
    return arr;
}

let list = fn(); //返回arr-数组
for(let i = 0,len = list.length;i < len;i ++){
    console.log(list[i]); // 5 * function(){retunr i}
}
/*
    分析:中间层函数自调用 函数的功能是返回五个函数块
    最里层的函数并没有执行
    此时arr拿到的值是中间层函数的返回值 五个函数块
    函数fn的返回值是arr 这里赋值给了list
    遍历输出list 结果就是五个函数块
    
*/
  1. 案例8:
//循环里的匿名函数的取值问题
function fn(){
    var arr = [];
    for(var i = 0;i < 5;i ++){
        arr[i] = function(){
            return i;
        }(i);
    }
    return arr;
}

let list = fn(); //返回arr-数组
for(let i = 0,len = list.length;i < len;i ++){
    console.log(list[i]); // 01234
}
/*
    分析:里层函数自调用 调用时传了一个实参
    由于该函数没有形参,所以实参忽略
    实参多余形参,多余的值忽略不计
    实参少于形参,多余的形参值为undefined
    函数功能是返回0,1,2,3,4;赋值给了arr
    函数fn的返回值是arr,这里赋值给了list
    遍历list 结果输出01234
*/
  1. 案例9:
//循环里的匿名函数的取值问题
function fn(){
    var arr = [];
    for(var i = 0;i < 5;i ++){
        arr[i] = function(i){ // 0  1  2  3  4
            return function(){
                return i;
            };
        }(i);
    }
    return arr;
}

let list = fn(); //返回arr-数组
for(let i = 0,len = list.length;i < len;i ++){
    console.log(list[i]()); // 01234
}
/*
    分析:中间层函数自调用 传参 0 1 2 3 4
    中间层函数的功能是返回一个函数块 也就是里层函数块
    由于里层函数没有调用,不会执行
    里层函数的功能是返回i 
    由于里层没有声明i所以向上查找 找到了0 1 2 3 4
    这时,里层函数的功能就是返回 0 1 2 3 4 由于没有调用所以不会执行
    中间函数的功能是返回里层函数块
    所以arr的值就是
    arr[0] = function(){return 0};
    arr[1] = function(){return 1};
    ....
    函数fn的返回值是arr;遍历list接收到了arr
    遍历list 依次调用list里的每一个函数
    结果就是01234
*/ 

总结

什么是闭包?

答:闭包就是函数嵌套函数

为什么要用闭包?

答:主要是为了在函数外面使用函数内部定义的局部变量

闭包的坏处?

答:大量使用闭包的话,会产生内存泄漏(IE)
如何解决?
答:将使用完的变量赋值为null。

闭包的原理?

答:利用了js的垃圾回收机制

  1. 正常情况下,一个函数调用完,就会立即释放存储空间,包括函数里面声明的变量
  2. 但是在回收垃圾的过程中,发现了这个变量正在被另外一个函数使用,那么这个变量就永远不会被回收。

闭包的基本语法?

  1. 在函数中返回一个匿名函数,匿名函数中返回要返回的变量
  2. 使用这个变量的方法?通过匿名函数自运行
  3. 闭包返回的是一个函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值