闭包的理解

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

function createComparisonFunction(propertyNmae){
    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;
        }
    };
}

这里写图片描述

1. 闭包产生的原因

在函数createComparisonFunction()中返回了一个匿名函数,创建了一个闭包。
当匿名函数被返回时,其作用域链包含外部函数createComparisonFunction的作用域链,这样匿名函数就能访问外部函数createComparisonFunction定义的变量了。(因为作用域链的访问机制)更重要的是外部函数执行完毕后,其作用域链销毁,但其活动对象不会销毁,因为在匿名函数的作用域链在引用它,直到匿名函数被销毁才会销毁。

2. 作用域链

作用域链的最前端是当前代码的执行环境的变量对象(活动对象),下一个变量对象是其的包含环境,再下一个是下一个的包含环境,这样作用域链的末端就是全局执行环境。内部环境在作用域链的最前端,外部环境在其后面。由于标识符解析沿着作用域链一级一级的搜索标识符直到找到。因此内部环境可以通过作用域链访问到所有外部环境,但是外部环境不能访问内部环境的任何变量和函数。

3.对于上图的解析

对于外部函数createComparisonFunction来说,它的作用域链最前端是自己的活动对象,里面存储着atguments和propertyName,接下来是它的包含环境即全局变量对象;对于匿名函数,它的作用域链最前端就是闭包本身的活动对象,里面存储arguments和object1,object2.接下来是其包含环境createComparisonFunction的活动对象,最后就是全局活动对象。

4.闭包和变量

闭包保存的是整个变量的对象而不是变量的某个特殊值,因此闭包智能取得任何变量的最后一个值。

function createFunction(){
    var result=new Array();
    for(var i=0;i<10;i++){
        result[i]=function(){
            return i;
        };
    }
    return result;
}

上面的函数结果输出全是10,这是因为每次调用匿名函数时其作用域链保存的都是createFunction()函数的活动对象,因此引用的都是同一个变量i。当createFuction()返回后,变量i的值都是10,此时每个匿名函数都引用者保存变量i 的同一个变量,所以在每个函数内部i的值都是10
那么要如何让闭包符合预期呢?

function createFunction(){
    var result=[];
    for(var i=0;i<10;i++){
        result[i]=function(num){
            return function(){
                return num;
            };
        }(i);
    }
    return result;
}

这样修改后能返回不同索引值是因为:没有把某一时刻i的特殊主直接赋值给数组,而是定义了一个立即执行的匿名函数将其赋值给数组。在这个匿名函数里面,接受i的特殊值作为参数,由于立即执行,此时将i的特殊值按值传递给num,而在立即执行的匿名函数内部又创建了一个访问num 的闭包,这样result数组的每个函数都有自己的num副本(保存i的特殊值),就让闭包的结果符合预期。

5.关于this对t象

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

var name='the  window';
var object={
    namw:'my object',
    getNamFunc:function(){
        return function(){
            return this.name;
        }
    }
};
alert(object.getNameFunc()());  //the window

上面调用object.getNameFunc(),返回的是the window而不是没有my object
我们把最后的一句拆成两个步骤执行:

var first = object.getNameFunc();
var second = first();
其中第一步,获得的first为返回的匿名函数,此时的getNameFunc()作为object的方法调用,如果在getNameFunc()中使用this,此时的this指向的是object对象。
第二步,调用first函数,可以很清楚的发现,此时调用first函数,first函数没有在对象中调用,因此是作为函数调用的,是在全局作用域下,因此first函数中的this指向的是window。
由于每个函数在被调用时会自动取得this.arguments,函数搜索时只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。
那么,如何获得外部作用域中的this呢?
可以把外部作用域中的this保存在闭包可以访问到的变量里。如下:

var name = "The Window";
var object = {
    name: "My object",
    getNameFunc: function() {
        var that = this;   // 将getNameFunc()的this保存在that变量中
        var age = 15;
        return function() {
            return that.name;
        };
    }
}
alert(object.getNameFunc()());   // "My object"

复制代码
其中,getNameFunc()执行时的活动对象有:that/age/匿名函数,在执行匿名函数时,同时引用了getNameFunc()中的活动对象,因此可以获取that和age的值。但是由于是在全局环境中调用的匿名函数,因此匿名函数内部的this还是指向window。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值