js闭包原理及使用

保持对代码的热爱并保持怀疑态度
昨天写了一篇点击查看js防抖和节流的理解用到了闭包,刚刚好我也忘的差不多了,只知道闭包长什么,原理什么的早就忘到九霄云外了,所以准备重新梳理了一下闭包。

闭包的概念及原理

闭包是指有权访问另外一个函数作用域中的变量的函数。
也可以这么说,这样可能更能理解,也就是闭包的原理
通过作用域的嵌套,触发计算机的垃圾回收机制(硬盘),将原本的局部变量进化成私有变量的环境,叫闭包

计算机的垃圾回收机制

  • 硬盘:需要删除的数据,不直接删除,而是再是保存在一个临时区域,如果需要继续使用,可以从临时区域取出

  • 内存:需要删除的数据,直接删除,不可恢复

  • 程序,或代码的执行,默认使用的是内存的垃圾回收,闭包使用的是硬盘的垃圾回收

实例

首先来看这么一个需求, 要求多次执行a的值累加,不允许出现全局变量

    function fn() {
        var a = 10;
        a++
        console.log(a);
    }
    fn()
    fn()

如果这么写的话,a只会输出11,因为函数每次都是重新执行。

但是这么写呢

    function fn() {
        var a = 10;
        return function(){
            a++;
            console.log(a);
        }
    }
    var f=fn();
    f();
    f();
    f();

很显然是可以实现累加的,没错这就是闭包
在这里插入图片描述

实例分析

在分析上诉代码中,首先得知道这么几个知识

关于函数的定义作用域和执行作用域

  • 定义函数时的作用域,叫定义作用域
  • 执行函数时的作用域,叫执行作用域
  • 无论函数在哪执行,都可以在自身内部使用自身定义作用域中的数据

拿上面的例子来分析

    function fn() {     定义
        var a = 10;      这个a相对于下面一个函数相当于是父级
        return function(){    定义返回值
            a++;       每次都累加a,这里也没有声明a,所以会直接会改变a的值,执行一次就改变一次,所以就实现了累加。
            console.log(a);
        }
    }
    var f=fn();  赋值
    f();   执行 ,函数在执行时,可以拿到自身的定义作用域的变量
    f();    
    f();

也可以这么写,通过传参的方式

    function fn(a) {
        此时的a是fn的形参。通过作用域的嵌套,a此时相当于返回函数的父级作用域  ,也可以实现累加
        return function(){      
            a++;
            console.log(a);
        }
    }
    var f=fn(10); 
    f();
    f();
    f();

闭包的特点

  • 可以在作用域外部修改作用域内部的数据
  • 连接了作用域内外部的桥梁
  • 消耗内存
  • 内存泄漏(内存溢出)(低版本浏览器以下)

闭包的应用

可以给内置的方法的回调函数传参

看实例

    setTimeout(fn("hello"), 1000);
    function fn(a){
        console.log(a);
    }

如果直接这么写的话,不会等到1秒钟以后再console.log,而是立即执行,为什么呢,涉及到了宏任务和微任务,点击查看异步,同步,宏任务,微任务理解但这不是重点,重点我们用闭包来解决这个问题

 setTimeout(fn("hello"), 1000);
    function fn(a){
        return function(){
            console.log(a);
        }
    }

这里就是通过传参的方式来解决的。

循环中的事件内使用循环的变量

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        
    </style>
</head>
<body>
    <ul>
        <li>link1</li>
        <li>link2</li>
        <li>link3</li>
        <li>link4</li>
        <li>link5</li>
    </ul>
</body>
<script>

    // 循环中的事件内使用循环的变量
    var ali = document.querySelectorAll("li")

    for(var i=0;i<ali.length;i++){
        (function(i){
            ali[i].onclick = function(){
                console.log(i);
            }
        })(i);
    }

    for(var i=0;i<ali.length;i++){
        ali[i].onclick = (function(i){
            return function(){
                console.log(i);
            }
        })(i);
    }

    for(let i=0;i<ali.length;i++){
        ali[i].onclick = function(){
            console.log(i);
        }
    }



</script>
</html>

以上的三种方式均可以获取到li的索引。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

划水的乌贼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值