• 谈谈JS中的闭包


    一、什么是闭包?

    看概念总是迷迷糊糊,好像懂了,却又说不清。在此引用别的博主的话:

      通俗地讲就是别人家有某个东西,你想拿到但是因为权限不够(不打死你才怪),但是你可以跟家里的孩子套近乎,通过他拿到!

      这个家就是局部作用域,外部无法访问内部变量,孩子是返回对象,对家里的东西有访问权限,借助返回对象间接访问内部变量!

      

    总结下有三个特点:

    • 函数嵌套函数

    • 内部的函数可以引用外部函数的参数或者变量

    • 参数和变量不会被垃圾回收机制回收,因为内部函数还在引用

            function aaa(){
                var a = 5;
                function bbb(){
                    console.log(a);
                }
                return bbb;
            }
            var c = aaa();     //此时c是aaa内部return的bbb函数体,外部函数aaa已运行完毕,但是变量仍被内部函数引用,故不会释放。
            c();   //打印结果是5
    

      

    二、闭包的好处

    • 变量可以长期驻扎在内存之中

    • 避免全局变量的污染,有私有成员

    下面看一下例子:

    1、普通函数调用:aaa执行完毕,就回收a变量,再次执行,重新赋值计算。

            function aaa(){
                var a = 1;
                a++;
                alert(a);
            }
            aaa(); //2
            aaa(); //2
    

    2、闭包方式调用:aaa执行后,由于a变量还在被内部函数引用,故不会被回收,再次计算,在上一次的结果上进行累加。

            function aaa(){
                var a = 1;
                return function(){
                    a++;
                    alert(a);
                }
            }
            var c = aaa();
            c(); //2
            c(); //3

    3、上面还可以改写成:

            var aaa = (function(){
                var a = 1;
                return function(){
                    a++;
                    alert(a);
                }
            })()  //函数表达式自执行,结果是内部函数体
            aaa(); //2
            aaa(); //3
    

    三、闭包的用途

    • 模块化代码


    var aaa = (function(){ //aaa是一个模块,私有变量是a,私有函数是bbb和ccc var a = 1; function bbb(){ a++; alert(a); } function ccc(){ a++; alert(a); } return { b:bbb, c:ccc } })() //函数表达式自执行,结果是return后面的对象 aaa.b(); //2 aaa.c(); //3
    • 在循环中找到索引
    <body>
        <ul>
            <li>111111</li>
            <li>111111</li>
            <li>111111</li>
        </ul>
        <script>
            window.onload = function(){
                var aLi = document.getElementsByTagName('li');
                for(var i=0;i<aLi.length;i++){
                    aLi[i].onclick = function(){
                        alert(i); //顺序点击三个li,分别弹出3 3 3。因为点击的时候for循环已经执行完毕
                    }
                }
            }
        </script>
    </body>
    

      可使用闭包改为:

    <body>
        <ul>
            <li>111111</li>
            <li>111111</li>
            <li>111111</li>
        </ul>
        <script>
            window.onload = function(){
                var aLi = document.getElementsByTagName('li');
                for(var i=0;i<aLi.length;i++){
                    (function(i){
                        aLi[i].onclick = function(){
                            alert(i); //0 1 2
                        }
                    })(i) //将i作为参数传递给内部函数,i 在for循环执行完毕不会被释放
                }
            }
        </script>
    </body>
    

      或者另一种写法:

    <body>
        <ul>
            <li>111111</li>
            <li>111111</li>
            <li>111111</li>
        </ul>
        <script>
            window.onload = function(){
                var aLi = document.getElementsByTagName('li');
                for(var i=0;i<aLi.length;i++){
                    aLi[i].onclick = (function(i){
                        return function(){
                            alert(i); 
                        }
                    })(i) //循环的时候,这个函数表达式自执行,i也是驻扎在内存当中。
                }
            }
        </script>
    </body>
    

      

    四、闭包需要注意的问题

    • 在IE下会引发内存泄露

    <body>
        <div id="div1">my div</div>
        <script>
            window.onload = function(){
                var oDiv = document.getElementById('div1');
                oDiv.onclick = function(){
                    alert(oDiv.id);
                }
            }
        </script>
    </body>
    

        当一个变量为一个dom节点获取或者宿主对象(此例子中为oDiv),它的一个属性(此例中为onclick)引用一个内部函数,而内部函数又在引用外部对象(此例中外部对象是oDiv)。会造成互相引用,引起内存泄露。

    • 如何解决:

        方法一:

    <body>
        <div id="div1">my div</div>
        <script>
            window.onload = function(){
                var oDiv = document.getElementById('div1');
                oDiv.onclick = function(){
                    alert(oDiv.id);
                }
    
                //卸载文档时候执行
                window.onunload=function(){
                    oDiv.onclick = null;
                }
            }
        </script>
    </body>
    

        方法二:

    <body>
        <div id="div1">my div</div>
        <script>
            window.onload = function(){
                var oDiv = document.getElementById('div1');
                //赋值给一个变量
                var oId = oDiv.id;
                oDiv.onclick = function(){
                    alert(oId);
                }
                //还要让对象对空
                oDiv = null;
            }
        </script>
    </body>
    

      

  • 相关阅读:
    poj 3661
    hdu 4291 && hdu 4296
    codeforces LCM Challenge
    ural 1286
    Exhange2007 专题(一)特性 部署
    Research Http error code
    Exhange2007 专题(二)通过Web service对Exhange进行二次开发
    YouTube 架构学习体会
    .net framework 4.0环境下遇到版本不同编译不通过的解决办法
    利用ASP.NET MVC2进行网站验证
  • 原文地址:https://www.cnblogs.com/jelina/p/11146345.html
Copyright © 2020-2023  润新知