JavaScript 高级之 闭包是什么

本文详细介绍了JavaScript中的闭包,包括其概念、作用及示例。闭包是一种机制,允许函数访问并操作外部函数的变量,延长变量的生命周期。文章通过实例解释了如何创建闭包,以及在点击事件中使用闭包解决变量引用问题。同时,提到了作用域、作用域链和垃圾回收机制等相关知识点,强调了正确理解和使用闭包的重要性。
摘要由CSDN通过智能技术生成

目录

1. 闭包的概念

2. 闭包的作用:

3. 闭包示例

3.1 点击li,输出当前li的索引号


闭包的概念:

第二次看自己的这篇文章,感觉原来的理解有些偏颇,进行完善。

闭包的概念:

1. 函数A内部声明并且返回了一个函数B,

2. 这个函数B被外部访问的同时,使用了函数A里面的变量或者是形参

3. 导致了函数A的作用域内的变量不能够被释放闭包产生了。函数B就是闭包,闭包也叫闭包函数。

来看如下闭包的代码和解释:

        function fn() {
            var num = 10;
            // function fun() {
            //     console.log(num);

            // }
            // return fun;
            return function () {
                console.log(num); // 10
            }
        }
        var f = fn();
        f();
        // f接受fn()函数的返回值,这个返回值就是一个函数,里面能够打印num变量
        // num变量 通过作用域链 访问到fn()这个函数的num值是10,
        // 此时,f接受的函数在外部,外部访问到了num变量 就是闭包的产生
        // 此时num变量的生命周期不会随着fn()函数的执行完毕而销毁。
        // 什么时候销毁呢? f变量销毁 =》其代表的函数也不销毁 =》num变量也就销毁

我们可以拆解为几个部分:

1. fn函数里面有内部的返回值且就是一个函数。

2. return的这个函数内部打印了num变量。为什么能够打印num变量,原因在于作用域链的访问机制,下面会补充作用域和作用域链的知识点。

3. 我们在外部用f变量接受了fn(),也就是接受了fn的返回值【内部函数】

4. 紧接着调用f,也就是调用了fn里面的内部函数。最终能够打印10

2022/2/25日 

再次读了下面这篇文章,有了进一步的理解。写在上面的代码块里面

对JavaScript中闭包的理解_王宜明的个人博客-CSDN博客_对闭包的理解

知识点的补充:

1. 作用域:

        变量在某个范围内起作用,超出了这个范围,就不起作用。这个范围就是作用域。作用域在函数的定义时就产生,而不是函数调用时产生的。

2. 作用域链

        一句话概括:根据【内部函数可以访问外部函数变量】,采用就近原则一层一层向上查找变量,这个机制就叫作作用域链。

        函数A包含了函数B,那么函数B就是函数A的内部函数,

        而内部函数如果要使用一个变量,首先看自己内部有没有这个变量,

        如果没有,就会去紧挨着的上一级查找,【就近原则】

        如果函数一层一层都找不到,最后才会去全局变量下面找。

        var a = 1;
        var b = 11;
        function fn1() {
            var a = 2;
            var b = '22';
            fn2();
            function fn2() {
                var a = 3;
                fn3();
                function fn3() {
                    var a = 4;
                    console.log(a); // 4
                    console.log(b); // '22'
                }
            }
        }
        fn1();

3. 垃圾回收机制

可以参考这位大哥对于JS垃圾回收机制的描述:

   https://segmentfault.com/a/1190000018605776

我们结合这三个概念看闭包的作用

2. 闭包的作用:

我们把函数A叫作外层的函数,这个函数内部有一个函数B

外部用一个变量f接受函数A的返回值【函数B

而函数A作用域的变量叫作num

1. 能够在函数的外部访问函数内部的变量【搭建外部访问内部作用域的通道】

        原理:上面其实有解释过。

        第一要理解,作用链的原理看上面。函数B能够调用函数A的变量num

        第二要理解,首先函数A的返回值是函数B【内部函数】,其次这个返回值要在函数外部用变量f接受,接受以后就能够调用函数B,函数B就会访问函数A的变量num。而这个内部函数B就是闭包函数啦。

2. 能够延长函数内部变量的生命周期。

        第一个作用带来第二个作用。js的变量存在垃圾回收机制,如果函数执行完毕,变量会被清除,内存也会消除。可是如果利用闭包,变量可以不被立即清除。

        原因是,外部的变量f接受了一个函数A的内部函数B,而这个内部函数访问了函数A作用域的变量num,只要函数B执行且变量f一直存在,那么变量num就会一直存在。不会因为函数A的执行结束就消失。

参考了下面的文章,讲的非常详细,推荐看。

对JavaScript中闭包的理解_王宜明的个人博客-CSDN博客

3. 闭包示例

后面会补充闭包的一些应用。

我们要想起什么场合用闭包,闭包不能滥用。

3.1 点击li,输出当前li的索引号

    <ul class="nav">
        <li>榴莲</li>
        <li>臭豆腐</li>
        <li>鲱鱼罐头</li>
        <li>大猪蹄子</li>
    </ul>
    <script>
        // 闭包应用-点击li输出当前li的索引号
        // 1. 我们可以利用动态添加属性的方式
        var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) {
            lis[i].onclick = function () {
                console.log(i); // 四个4
            }
        }
    </script>

原理:上图这样写,打印出来的i永远都是4。原因是,此时首先是非严格模式,在非严格模式下,for循环是同步执行任务,而按钮点击再执行是异步任务,同步执行完毕,i加到了4.再执行异步任务打印i,都是4。

改法1:用闭包

1.for循环生成四个立即执行函数

2. 立即执行函数是闭包的一种应用。立即执行函数里面的所有函数包括【点击 回调】函数都可以使用立即执行函数的传递的形参。

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

                }
            })(i);
        }

改法2:var--->let

点击对应小li,打印i是对应索引号。使用let是ES6语法,此时for有块级作用域

        var lis = document.querySelector('.nav').querySelectorAll('li');
        for (let i = 0; i < lis.length; i++) {
            lis[i].onclick = function () {
                // console.log(i);
                console.log(i);
            }
        }

改法3:用设置自定义属性index的方法

        var lis = document.querySelector('.nav').querySelectorAll('li');
        for (var i = 0; i < lis.length; i++) { // 注意这里是var不是let
            lis[i].index = i; // 注意这里是lis[i]不是this.index,此时没有点击,哪里来的this
            lis[i].onclick = function () {
                console.log(this.index);
            }
        }

---------------------------

有待2 次更新

结尾:

学习id: 201903090124-37

现在是大三学生,学习到了vue阶段,如有不对的地方,欢迎指正,一起努力呀。如有转载请注明出处

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值