JavaScript闭包的理解

JavaScript闭包的理解
一、闭包的概念:闭包就是能够读取其他函数内部变量的函数。例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
当然,以上解释来自百度百科,对于一些人来说可能看了还是蒙蒙的,接下来看一下闭包是怎么形成的
二、闭包的形成
(1)在认识闭包对全局变量和局部变量进行理解:

var  f1 = 2;
function fn1(){
var  f2 = 3;
function fn2(){
var  f = f1 + f2;
} 
fn2();
}
fn1();

顾名思义,全局就好比我们生活的区域一样,生活中的公共区域就好比全局,我们各自的家就好比是局部
在以上代码中,可以看到fn1的定义和执行都在全局,fn2的定义和执行是在fn1的内部,f1就是在全局声明的,f2是在函数fn1的局部声明的,而f这是在fn2的局部声明的。

(2)现在对全局和局部有了了解后,再做一个小测试:

function fn1(){
var  a = 3;
var num = 0;
num += a;
console.log(num);
}
fn1();
fn1();
fn1();

在这里插入图片描述
可以看到,每次拿到的num都是3,这是因为,每次执行fn的时候都重新声明了a和num。如果想每次拿到的num都加上3怎么做呢?

(3)那么就让a和num只声明一次,把a和num放在全局声明,再局部只是作值的改变,请看下面的改变:

var a = 3;
var num = 0;
function fn1(){
num += a;
console.log(num);
}
fn1();fn1();fn1();

输出结果:
在这里插入图片描述
这样就拿到的num就在原基础上加3。

(4)对上面的代码封装,把函数fn2返回出来,并执行,依然可以拿到3,6,9

function fn1(){
var a = 3;
var num = 0;
return function fn2(){
num += a;
console.log(num);
}
}
var f = fn1();
f();f();f();

输出结果:
在这里插入图片描述
接下来做一点优化,把函数fn1放在匿名函数中自动执行,因为匿名函数自动执行,f();就是执行了函数fn2。

var f = (function fn1(){
        var a = 3;
        var num = 0;
        return function fn2(){
            num += a;
            console.log(num);
        }
    })();
    f();
    f();
    f();

输出结果:

在这里插入图片描述
以上就是一个简单闭包的演化过程。
简单的说闭包就是利用函数的嵌套,在外部函数外面控制外部函数的局部变量。

闭包的开始和结束:

var f = (function fn1(){
        var a = 3;
        var num = 0;
        return function fn2(){			// 闭包开始
            num += a;
            console.log(num);
        }
    })();
    f();
    f = null;						// 闭包结束
    f();	

输出结果:
在这里插入图片描述

三、闭包的特点
(1)闭包可以让全局变量私有化:

下面的a和num变量是全局变量:如代码1 私有化后:如代码2

(2)可以在函数的外部修改函数内部的变量:
可以看到以上代码中,函数fn2对函数fn1的局部变量a和num进行了操作
(3)作用域不销毁:
是因为执行完外部函数fn1后,函数fn2保存了fn1的局部变量,导致fn1执行结束后没有立即释放内存,所以作用域没有销毁。

四、闭包应用:
(1)可以在循环的点击事件里面获取到指定的索引

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<style>
    div{width:100px;height: 100px;background-color: #f00;margin: 10px;}
</style>
<body>
    <div class ="box1">1</div>
    <div class ="box2">2</div>
    <div class ="box3">3</div>
    <div class ="box4">4</div>
</body>
<script>
    var abox = document.querySelectorAll("div");
    for(var i = 0;i < abox.length;i++){
        abox[i].onclick = function(){
            console.log(i);
        }
    }
</script>
</html>

输出结果:
在这里插入图片描述

可以看到每次点击后,得到的i都是最后一个索引,这是因为循环是一瞬间的,当点击的时候,循环已经结束了。
于是可以利用闭包的特点拿到每个索引:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<style>
    div{width:100px;height: 100px;background-color: #f00;margin: 10px;}
</style>
<body>
    <div class ="box1">1</div>
    <div class ="box2">2</div>
    <div class ="box3">3</div>
    <div class ="box4">4</div>
</body>
<script>
    var abox = document.querySelectorAll("div");
    for(var i = 0;i < abox.length;i++){
        (abox[i].onclick = function(i){
            console.log(i);
        })(i);
    }
</script>
</html>

输出结果:
在这里插入图片描述
以上代码也可以使用ES6的新增关键字let解决,因为let内部实现了闭包机制。

(2)闭包实现代码的模块化:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<style>
</style>
<body>
</body>
<script>
    var f = (function fn(){
        return{
            show:function(q){
                console.log("方法一"+q);
            },
            say:function(q){
                console.log("方法二"+q);
            }
        }
    })();
    f.show(2);
    f.say(5);
</script>
</html>

输出结果:
在这里插入图片描述

总结:闭包虽然解决了全局变量,但是大量的使用闭包,会消耗内存,甚至可能导致内存泄漏,所有要按需使用。以上只是个人对闭包的简单描述,如有不正确的地方,希望读者可以指出改正,疫情期间,逆战加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值