zoukankan      html  css  js  c++  java
  • 闭包

    变量的作用域以及作用域链

    延长变量的作用域

    请看下面的例子

    function f1(){
            var n=a;
            function f2(){
                alert(n); // a
            }
            //f2();
        }

    上面的代码很简单,我们在f1里面去调用f2()当然可以弹出n的值a,但是如果我们在外部全局执行环境里面还要获得n的值,这又该怎么办?这就是刚刚的提问,外部的执行环境要求访问内部执行环境的值。

     从外往里访问,这里就可以通过闭包来实现这个效果,把上面的代码稍作修改:

        function f1(){
            var n=999; //私有变量
        
            //在函数f1内定义另外的函数作为f1的方法函数
            function f2(){
                alert(n); //引用外层函数f1的临时变量n
            }
            return f2; //返回内部函数
        }
        //调用函数
        var result=f1();
        result(); // 999

    当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包

    实际应用中会遇到闭包的情况

     界面上有一组a标签,分别点击,希望点击不同的a标签弹出不同的结果,代码如下:

        <ul>
            <li><a href="#">第0个链接</a></li>
            <li><a href="#">第1个链接</a></li>
            <li><a href="#">第2个链接</a></li>
            <li><a href="#">第3个链接</a></li>
        </ul>    
        
        var as = document.getElementsByTagName("a");
        for(var i=0;i<as.length;i++){
            as[i].onclick = function(){
                alert("你现在单击的是第" + i + "个链接");
            }
        }

    上面这段代码的估计大家都遇到过类似的,想要的效果和实际出现的效果不一致,本来想点击每一个,弹出不同的i的值,但是没想到最后弹出的i的值都是4。
    这正是由于变量的作用域链影响造成的,因为在用户单击a标签的时候才会调用onclick指向的匿名函数。而调用时,需要得到变量i的值,js解析程序首先会在匿名函数内部查找i,但是没有定义。于是往外找,在外部执行环境中找到变量i,但是这个i已经被循环到4了,因为for循环在页面初始化的时候已经被执行了。所以匿名函数里面的i实际上取得的是外部作用域链中i的值。想要改正这个错误,其实就是把i的值传入到匿名函数值就行了。但是匿名函数又不能传值。这个时候,我们就可以用闭包。
    先创建这样一个函数:

        function closureTest(num){
            return function(){
                alert("你现在单击的是第" + num + "个链接")
            }
        }

    这个函数直接返回了一个匿名函数,之前讲过闭包,所以,当返回的这个函数在外部被接收的时候,__外层函数closureTest里的变量num,就会被保存起来__,所以,将之前循环的代码修改一下:

        for(var i=0;i<as.length;i++){
            as[i].onclick = closureTest(i);
        }

    循环里面onclick调用的函数closureTest,并传入了参数i,而closureTest返回了匿名函数,所以根据闭包的原理,传入的参数i,就被保存在了内存当中,外部访问的就是每次不一样的值了。当然,你也可以直接写成下面这个样子:

        for(var i=0;i<as.length;i++){
            as[i].onclick = (function(i){
                return function(){
                    alert("你现在单击的是第" + i + "个链接")
                }
            })(i);
        }

  • 相关阅读:
    ArcGIS Engine 中的多线程使用
    Arcgis栅格时序地图制作---时间轴动态展示多期影像
    R树空间索引
    R-Tree空间索引算法的研究历程和最新进展分析
    学生表、课程表、 成绩表 、教师表sql练习
    Mysql建表出现1005错误
    MySQL数据类型详解
    数据库操作语句类型(DQL、DML、DDL、DCL)简介
    Spring MVC标签<mvc: annotation-driven />小结 原
    EasyUI Menu 菜单
  • 原文地址:https://www.cnblogs.com/huzhen/p/4095366.html
Copyright © 2011-2022 走看看