zoukankan      html  css  js  c++  java
  • Javascript之匿名函数(闭包与变量)

    1.闭包与变量

     JavaScript中的作用域链的机制引出了一个副作用,即闭包只能取得包含函数中任何变量的最后一个值。闭包所保存的是整个变量对象,而不是某个特殊的值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function createFunctions(){ 
        var result=new Array(); 
            
        for (var i=0;i<10;i++){ 
            result[i]=function(){ 
                return i; 
            }; 
        
        return result; 
    var funcs = createFunctions(); 
    for (var i=0; i < funcs.length; i++){ 
        document.write(funcs[i]() + "<br />"); 
    }

    createFunction()函数返回一个数组。表面上看,似乎每个函数都应该返回自己的索引值,但事实并非如此,事实上每个函数的返回值都是10.因为每个函数的作用域链中都包含着createFunctions()函数的活动对象,所以它们引用的都是同一个变量i。当createFunctions()函数返回后,变量i的值就是10,此时每个函数都引用着保存变量i的同一个变量对象,所以每个函数返回后都是10.

    当然我们可以使用匿名函数强制使闭包的行为符合预期。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function createFunctions(){  
        var result=new Array();  
              
        for (var i=0;i<10;i++){  
            result[i]=function(num){
                return function(){  
                return num;  
            };  
            }(i);
        }  
        return result;  
    }  
    var funcs = createFunctions();  
    for (var i=0; i < funcs.length; i++){  
        document.write(funcs[i]() + "<br />");  
    }

    在重写了前面的createFunctions()函数后,每个函数就好返回各自不同的索引值了。在这里,我们没有直接把闭包赋值给数值,而是定义了一个匿名函数,并将立即执行该函数的结果赋值给数组。这里的匿名函数有一个参数num,也就是最终的函数要返回的值。在调用每个匿名函数时,我们传入了变量i。由于函数参数按值传递的,所以就会将变量i的当前值复制给参数num。而在这个匿名函数内部,有创建并返回了一个访问num的闭包。这样依赖,result数组中的每个函数都有自己num变量的一个副本,因此就可以返回各自不同的数值了。

    1.2关于this对象

    在闭包中使用this对象会出现一些问题,this对象是运行时基于函数的执行环境绑定的:在全局函数中,this等于window,而当函数被当作某个对象的方法调用时,this等于那个对象。不过,匿名函数的执行环境具有全局性,因此其this对象通常指向window(当然,在通过call()和apply()改变函数执行环境时,this指向其他对象)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var name="The Window"
        
    var object={ 
        name:"My object"
        getNameFunc:function(){ 
            return function(){ 
                return this.name; 
                }; 
            
        }; 
    alert(object.getNameFunc()()); //"The Window"(在非严格模式下)

    以上代码创建了一个全局变量name,有创建了一个包含那么属性的对象,这个对象还包括一个方法——getNameFunc(),它返回一个匿名函数,而匿名函数又返回this.name.由于getNameFunc()返会一个函数。因此调用object.getNameFunc()()就会立即返回调用它的函数,结果就返回一个字符串。然而,这个例子返回的字符串是“The Window”,即全局name变量的值。

    但是,为什么匿名函数没有取得其包含作用域(或外部作用域)的this对象呢?

    每个函数在调用时,其活动对象都会自动获取两个特殊的变量:this和arguments。内部函数在搜索这两个变量时,只会搜到其活动对象为止,因此永远不肯能访问到外部函数中的这两个变量。不过,把外部作用域中的this对象保存在一个闭包能够访问的变量里,就可以放闭包访问该对象了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var name="The Window"
        
    var object={ 
        name:"My object"
        getNameFunc:function(){ 
            var that=this;
            return function(){ 
                return that.name; 
                }; 
            
        }; 
    alert(object.getNameFunc()()); //"My object"

     以上代码中,我们在定义匿名函数之前,把this对象赋值给了that变量,而在定义闭包之后,闭包也可以访问这个变量,因为它们是我们在外部函数中特意声明的一个变量。即使在函数返回之后,this也仍然引用的object,所以调用object.getName()()就返回“My object”.

    1.3内存泄漏

    由于IE9之前的版本对JS对象和COM对象使用不同的垃圾回收历程,因此闭包在IE中会导致一些特殊的问题。具体来说,如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素将无法被销毁。

    1
    2
    3
    4
    5
    6
    function assignHandler(){
        var element=document.getElementById("someElement");
        element.onclick=function(){
             alert(element.id);
        };
    }

    以上代码创建了一个作为element元素事件处理程序的闭包,而这个闭包则有创建了一个循环引用。由于匿名函数保存了对assignHandler()的活动对象的引用,因此就会导致无法减少element的引用数,也就无法回收该对象。

    不过可以通过一下代码来解决。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function assignHandler(){ 
        var element=document.getElementById("someElement"); 
        var id=element.id;
      
        element.onclick=function(){ 
             alert(id); 
        }; 
        element=null;
    }




  • 相关阅读:
    atitit.TokenService v3 qb1 token服务模块的设计 新特性.docx
    Atitit attilax在自然语言处理领域的成果
    Atitit 图像清晰度 模糊度 检测 识别 评价算法 原理
    Atitit (Sketch Filter)素描滤镜的实现  图像处理  attilax总结
    atitit。企业的价值观 员工第一 vs 客户第一.docx
    Atitit 实现java的linq 以及与stream api的比较
    Atitit dsl exer v3 qb3 新特性
    Atititi tesseract使用总结
    Atitit 修改密码的功能流程设计 attilax总结
    atitit.TokenService v3 qb1  token服务模块的设计 新特性.docx
  • 原文地址:https://www.cnblogs.com/zxj159/p/3107922.html
Copyright © 2011-2022 走看看