zoukankan      html  css  js  c++  java
  • Javascript 笔记与总结(1-5)闭包

    【例1】

    <script>
    function t1(){
        var age = 20;
        function t2(){
            alert(age);
        }
        return t2;
    }
    var tmp = t1();
    var age = 99;
    tmp();
    </script>

    弹出 20

    【分析】

    function t1(){
        var age = 20;
        function t2(){
            alert(age);
        }
        return t2;
    }

    在大部分的语言中,t1 被调用执行,则申请内存,并把其局部变量 push 入栈,t1 函数执行完毕,内部的局部变量,随着函数的退出而销毁,导致 age = 20 的局部变量消失。

    因此,t1(); 执行完毕之后,按 C 语言的理解,t1 内的局部变量都释放了。

    function t1(){
    
        var age = 20;
        function t2(){
            alert(age);
        }
    return t2;
    }

    在 js 中,t1 执行过程中,又生成了 t2,

    而从作用域上来说,t2 能访问到 age = 20,

    于是 “ age = 20 ” 没有消失,而是被 t2 捕捉到了,

    同时 “ age = 20 ” 与返回的 t1 函数形打了个包返回来了,成了一个 “ 环境包 ”,

    这个包属于 t2,所以叫 “ 闭包 ”。

    t2 把周围的环境打了包,也就是说 t2 是由自己的生态环境的,

    即 即使t1 执行完毕,通过 t2 ,依然能访问该变量:这种情况,函数并非孤立的函数,甚至把其周围的变量环境,形成了一个封闭的环境包,共同返回

    一句话概括:函数的作用域取决于声明时,而不取决于调用时

    【例2】

     1 function prev(){
     2     var leg = "Alexis";
     3     var arsenal_leg = function(){
     4         return leg;
     5     } 
     6     return arsenal_leg; //前半赛季阿森纳的大腿是桑切斯
     7 }
     8 
     9 function after(){    //来到了后半赛季
    10     var leg = "Giroud";
    11     var arsenal_leg = prev();    //调用prev(),arsenal_leg 函数来到了后半赛季
    12     alert(arsenal_leg());
    13 }
    14 after();    //谁是大腿
    15 
    16 </script>

    弹出:Alexis

    【分析】:

    line:14 执行 after();

    line:12 alert arsenal_leg();

    line:11 aesenal_leg() = prev();

    line:6  return  arsenal_leg();

    line:3  函数声明 return leg;【真正执行的函数】

    line:2  var leg = "Alexis";【作用域要从 函数声明之时寻找】

     

    例3闭包计数器,多人开发 js 程序,需要一个全局的计数器

    解决方案① 设立一个全局变量

    window.cnt = 0;

    调用 ++window.cnt

    这个方案可行但是,污染了全局变量;其次比人的程序中,也可能会含有 window.cnt = ***; 则该计数器就会被损坏(所以要避免使用全局变量)

    方案② 使用闭包维护一个别人污染不到的变量做技术器

    <script>
    
    function counter(){
        var cnt = 0;
        var cnter = function (){
            return ++cnt;
        }
        return cnter;
    }
    
    var inc = counter();
    alert(inc());
    alert(inc());
    alert(inc());
    
    </script>

    弹出 3 次,分别是:1,2,3

    简化上面的程序:

    <script>
    
    var inc = (function counter(){
        var cnt = 0;
        return function (){
            return ++cnt;
        }
    })();
    
    alert(inc());
    alert(inc());
    alert(inc());
    
    </script>

    再改版上面的程序(inc 依然是全局变量。在工作中,一般避免全局污染或冲突):

    方案 ① 统一放在一个全局对象上,如 jQuery -> $

    <script>
    
    $ = {}; 
    //模拟jQuery
    $.cnt = (function(){
        var cnt = 0;
        return function cnter(){
            return ++cnt;
        }
    })();
    
    alert($.cnt());
    alert($.cnt());
    alert($.cnt());
    
    </script>

    方案 ② 每个人使用自己的命名空间(其实就是把自己的变量、函数都放在一个对象里)

    <script>
    
    var Dee = {}; //一般用姓名做命名空间
    Dee.cnt = (function(){
        var cnt = 0;
        return function cnter(){
            return ++cnt;
        }
    })();
    
    alert(Dee.cnt());
    alert(Dee.cnt());
    alert(Dee.cnt());
    
    </script>

    【例4】要求:点击 4 个 li,分别弹出 0,1,2,3

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <ul>
            <li>阿森纳</li>
            <li>切尔西</li>
            <li>曼城</li>
            <li>利物浦</li>
        </ul>
    </body>
    <script>
    
    for(var i = 0, lis = document.getElementsByTagName("li"), len = lis.length; i < len; i++){
        lis[i].onclick = (function(i){
            return function(){
                alert(i);
            }
        })(i);
    }
    
    </script>
    </html>      

     【错误的写法】(会弹出 4,4,4,4):

    <script>
    
    for(var i = 0, lis = document.getElementsByTagName("li"), len = lis.length; i < len; i++){
        lis[i].onclick = function(){
            alert(i);
        }
    }
    
    </script>

    【错误的写法分析】:

    (回答者杨志):

    " 这个for循环会立即执行完毕,那么当onclick触发时,inner function查找变量 i 时,会在AO+scope中找,AO中没有,scope中的变量i已经成为 link.length. ",

    在运用了闭包之后,

    " 这时,如果inner function被触发,他会从自己的AO以及scope(outer function的AO 和 window scope)中找寻变量i. 可以看到outer function的AO中已经包

    含了i,而且对于这个for循环,会有对应有N个(function(){})() 被创建执行。所以每个inner function都有一个特定的包含了变量 i 的outer function。这样

    就可以顺利输出0,1,2,3 。

    结论: 我们可以看到,闭包其实就是因为Scope产生的,所以,广义上来讲,所有函数都是闭包。"

    " 所谓的异步函数,是包括ajax,事件触发,setTimeout , setInterval等回调的函数。

    当解析文档流时如果遇到js代码,会立即执行。如果这期间有异步函数被触发,会被存放在队列结构中。当之前的代码执行完毕后,浏览器查看此队列,如有待执行

    函数,则执行;没有则等待触发。

    所以,那个i 值会成为最大的那个。因为for循环在异步函数被执行前,已经跑完了。"

    参考:关于 Js 循环添加事件时闭包的影响有哪些解法?

  • 相关阅读:
    织梦开发——相关阅读likeart应用
    织梦标签教程
    织梦专题调用代码
    HIT 2543 Stone IV
    POJ 3680 Intervals
    HIT 2739 The Chinese Postman Problem
    POJ 1273 Drainage Ditches
    POJ 2455 Secret Milking Machine
    SPOJ 371 Boxes
    HIT 2715 Matrix3
  • 原文地址:https://www.cnblogs.com/dee0912/p/4433714.html
Copyright © 2011-2022 走看看