zoukankan      html  css  js  c++  java
  • js 闭包

    深入理解JS闭包
    关于JS中闭包的理解,相信很多人都和笔者一样刚开始很是困惑。笔者也是在看了很多前辈的文章后,总结出一点自己的理解。记录与此,囿于笔者水平有限 ,若有错误之处,恳请不啬赐教。

    你可以在一个函数里面嵌套另外一个函数。嵌套(内部)函数对其容器(外部)函数是私有的。它自身也形成了一个闭包。一个闭包是一个可以自己拥有独立的环境与变量的的表达式(通常是函数,因为ES6有了块级作用域的概念)。

    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Functions(上面这句话摘自这个网址)

    第一部分:初遇闭包
    http://www.runoob.com/js/js-function-closures.html

    什么是闭包?闭包有什么作用?这是我遇到闭包时的第一反应。

    闭包在JavaScript高级程序设计(第3版)中是这样描述:闭包是指有权访问另一个函数作用域中的变量的函数。

    那么闭包的作用也就很明显了。

    1. 可以在函数的外部访问到函数内部的局部变量。 
    2. 让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。

    在上面的代码中,闭包指的就是function () {return counter += 1;}这个函数。首先解释一下这段代码,在变量add被赋值之前,第一个function执行了一次(执行且仅会执行一次),因为这是一个函数表达式声明方式并且声明后加上了(),所以会自动执行一次。执行后add被赋值(匿名函数)了,add= function () {return counter += 1;} 。然后每次调用add()函数时,返回的都是这个函数,因为这个函数在第一个函数的内部,所以即使第一个函数执行完了,第二个函数依然能访问counter(JS设计的作用域链,当前作用域能访问上级的作用域)。

    闭包是可以在另一个函数的外部访问到其作用域中的变量的函数。而被访问的变量可以和函数一同存在。即使另一个函数已经运行结束,导致创建变量的环境销毁,也依然会存在,直到访问变量的那个函数被销毁。当然,如果仅仅是做一个简单的计数器,大可不用这样麻烦。下面这简短的代码就能轻松实现。

    var a = 0;
    function myFunction(){
    a++;
    document.getElementById("demo").innerHTML = a;
    }
    推荐一篇博客:https://blog.csdn.net/qq_36276528/article/details/70049825(写得很有深度)

    第二部分:牛客翻船
    https://www.nowcoder.com/questionTerminal/da4115e308c948169a9a73e50d09a3e7

    下面是这个题目的解答:
    每个li标签的onclick事件执行时,本身onclick绑定的function的作用域中没有变量i,i为undefined,则解析引擎会寻找父级作用域,发现父级作用域中有i,且for循环绑定事件结束后,i已经赋值为4,所以每个li标签的onclick事件执行时,alert的都是父作用域中的i,也就是4。这是作用域的问题。

    闭包只能取得包含函数中任何变量的最后一个值。因为别忘了闭包所保存的是整个变量对象,而不是某个特殊的变量。

    这是在循环体中创建闭包的常见错误。https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures(一定要看这篇)

    这里面给onclick赋值的是闭包。很多人会问为什么是闭包?之前闭包不是函数A里的函数B吗?函数B用来访问函数A的变量,称函数B是闭包,题目中只有一个函数为什么也是闭包。其实,用两个函数形成闭包只是一般形式。闭包真正的含义是,如果一个函数访问了此函数的父级及父级以上的作用域变量,就可以称这个函数是一个闭包。

    <script>
        var a = 1;
        (function test (){
    alert(a);
    })()
    </script>
    所以上面的function都可以称之为闭包(匿名闭包函数)。

    这里还是作用域的问题,那么我们把每次的i都保存到一个变量中,匿名闭包就可以实现想要的效果。

    var elements=document.getElementsByTagName('li');
        var length=elements.length;
        for(var i=0;i<length;i++){
            elements[i].οnclick=function(num){
            return function() {
                    alert(num);
            };
        }(i);
        }
    这样就使用了闭包,这里面的闭包指的是function() {alert(num);};第二个function里面弹出的num是第一个function的参数,通过(i)执行了这里面的第一个函数,同时i的值被保存到num中。每个点击事件中都有一个局部变量num,num保存的是相应的i值。

    第三部分:let的横空出世
    上面的牛客题目只需要将for(var i=0;i<length;i++)中的var改成let就能实现想要的效果,这让在循环体内创建闭包具有更好的可读性。let的简单介绍:https://mp.csdn.net/postedit/81065540

    let的到来,让令人诟病的JS获得了一丝生机,也补上了JS没有块级作用域的短板。ECMAScript6还有很多新特性,笔者也在不断学习中。

    第四部分:闭包的应用
    函数工厂和闭包模拟私有方法

    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures(这篇讲得很好,希望读者们读透)

    原文链接:https://blog.csdn.net/cauchy6317/article/details/81167572

  • 相关阅读:
    16款优秀的Vue UI组件库推荐
    通过论证:查询字段通常返回引用,该引用可以保证是原来的对象的状态的一部分。分析变量在内存中的变化过程。
    使用XtraReport的CalculatedFiled(计算字段)实现RDLC报表中表达式
    Task:取消异步计算限制操作 & 捕获任务中的异常
    webAPI 自动生成帮助文档
    live writer 博客测试
    c#基础 函数传值
    Google,真的要离我们而去吗?
    匹配中文字符的正则表达式: [/u4e00-/u9fa5]
    希尔排序的实现
  • 原文地址:https://www.cnblogs.com/yanan-boke/p/12273580.html
Copyright © 2011-2022 走看看