js 闭包

1、定义函数:

(1)函数声明

function 函数名(){}//指定函数名的方式

它的一个重要特征是函数声明提升,在执行代码之前会先读取函数声明。

(2) 函数表达式

var FunctionName = function(arg0, arg1, arg2){}//匿名函数

在使用之前必须先赋值。

2、闭包

  闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。

  每个函数都有自己的执行环境。每个执行环境都有一个与之相关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。当执行流进入到一个函数时,函数的环境会被推入一个环境栈中,而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。

  如果这个环境是函数,则将其活动对象作为变量对象。

  在创建某个函数时,会创建一个预先包含全局变量对象的作用域链,这个作用域链被保存在内部的[[Scope]]属性中。当调用函数时,会为函数创建一个执行环境,然后通过复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链。此后,又有一个活动对象(在此作为变量对象使用)被创建并推入执行环境作用域链的前端。作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。

 示例1:

 function compare(value1, value2){
        if(value1 > value2){
            return 1;
        }else if(value1 < value2){
            return -1;
        }else{
            return 0;
        }
 }
 compare(2, 10);

在另一个函数内部定义的函数会将包含外部函数的活动对象添加到它的作用域链中。

示例2:

   function createComparisionFunction(propertyName){
        
        return function(object1, object2){
            var value1 = object1[propertyName];
            var value2 = object2[propertyName];
            
            if(value1 > value2){
                return 1;
            }else if(value1 < value2){
                return -1;
            }else{
                return 0;
            }
        };
    }
    //创建函数。匿名函数被返回后,它的作用域链被初始化为包含createComparisionFunction()函数的活动对象和全局变量对象
    var compareNames = createComparisionFunction('name');

    //调用函数。createComparisionFunction()函数执行完毕后,其活动对象也不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象
    var result = compareNames({name: 'Tom'}, {name: 'Lucy'});

    //解除对匿名函数的引用,以便释放内存。匿名函数被销毁后,createComparisionFunction()的活动对象才会被销毁
    compareNames = null;

由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存,建议只在绝对必要时再考虑使用闭包。

3、闭包与变量

作用域链这种机制引出来一个副作用,即闭包只能取得包含函数中任何变量的最后一个值。

   function createFunction(){
        var result = new Array();
        
        for(var i = 0; i < 10; i++){
            result[i] = function(){
                return i;
            }
        }
        
        return result;
    }
    //createFunction()函数返回一个函数数组。函数返回后,变量i的值是10,此时每个函数都引用着保存变量i的同一个变量对象,所以每个函数内部i的值都是10。

    function createFunction(){
        var result = new Array();
        
        for(var i = 0; i < 10; i++){
            result[i] = function(num){//定义匿名函数
                return function(){//闭包
                    return num;
                };
            }(i);
        }
        
        return result;
    }


    //重写后的createFunction(),每个函数就会返回各自不同的索引值了。这个版本中,定义了一个匿名函数,并将立即执行该匿名函数的结果赋值给数组。在调用每个匿名函数时,出入变量i,因为函数参数是按值传递的,所以会将变量i当前的值复制给参数num,在这个匿名函数内部,创建并返回了一个访问num的闭包。

4、关于this对象

  匿名函数的执行环境具有全局性,因此其this对象通常指向window。

  每个函数在调用时,其活动对象都会自动取得this和arguments这两个特殊变量。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。

    var name = 'The window';
    
    var object = {
        name:'myproject',
        
        getnameFunc:function(){
            var that = this;
            return function(){
                return that.name;
            };
        }
    };
    
    var getname = object.getnameFunc();
    console.log(getname());//‘myproject’

 


  

posted @ 2015-12-10 16:33  tianxintian22  阅读(501)  评论(0编辑  收藏  举报