JS闭包

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

先从简单的例子开始:

function comparison(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;
            }
        };
    }
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

上面的函数comparison()中返回的匿名函数就是一个闭包,在这个匿名函数中,访问了外部函数中的变量propertyName,这个内部函数被返回之后,在其它地方调用时,仍然可以访问变量propertyName,原因是因为内部函数的作用域链包含外部函数comparison()的作用域。

var compare  = comparison("age");
var result = compare({"age": 25},{"age": 35});
console.log(result); //25, 35
 
 
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

在comparison()函数被调用时,会新建一个包含arguments和propertyName的活动对象,var compare = comparison(“age”);返回匿名函数,匿名函数的作用域链被初始化为包含comparison()函数的活动对象和全局变量对象。在comparison()函数执行完毕后,其执行环境的作用链会被销毁,但是活动对象不会,因为匿名函数的作用域链要引用这个活动对象。 
compare返回的是内部的匿名函数,即:下面的这个函数

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

在第二部,var result = compare({“age”: 25},{“age”: 35})时,传入了object1和object2,但是并没有传入propertyName,但是函数仍然可以返回正确的结果,就是因为这时访问的是外部函数comparison()的活动对象propertyName的值”age”。外部函数的活动对象不会被销毁,除非你们函数被销毁。 
如果我们在最后加上一句:

compare = null;
 
 
  • 1
  • 1

这就解除了对匿名函数的引用。垃圾回收例程才会将其清除,否则其将一直存在于内存之中,因为垃圾回收例程不知道何时它还会被再使用。由于闭包会携带包含它的函数的作用域,因此会比其它函数占用更多的内存,因此要避免过度使用闭包。

function newFunctions(){
        var result = new Array();
        for(var i = 0; i < 10; i++){
            result[i] = function(){
                return i;
            }
        }
        return result;
    }
    var values = newFunctions();//返回长度为10的函数数组
    console.log(values[2]());      //10
    console.log(values[5]());      //10
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

可以看出,values[2]()values[5]()并没有像我们料想中的那样返回2,和5,而是全部返回的是10,这是因为,每个函数的作用域中都保存着newFunctions()函数的活动对象,因此它们引用的是同一个变量i。当newFunctions()返回时,变量i的值都是10。此时,每个函数引用的都是保存变量i的同一个变量对象,因此每个函数内部的i的值都是10.

可以通过创建一个匿名函数强制让闭包的行为符合预期。

function newFunctions(){
        var result = new Array();
        for(var i = 0; i < 10; i++){
            result[i] = function(num){
                return function(){
                   return num;
                }
            }(i);
        }
        return result;
    }
    var values = newFunctions();//返回长度为10的函数数组
    console.log(values[2]());  //2
    console.log(values[5]());  //5
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

定义一个匿名函数,并将立即执行该匿名函数的结果赋值给数组。匿名函数有一个参数num,也是函数最终要返回的值。在每次调用这个函数时,都传入了一个变量i,每次将i的当前值复制给参数num。在这个匿名函数的内部,又创建并返回num的闭包。这样,result数组中的每个函数都有自己num变量,而不是像之前一样,全部都引用同样的一个i变量,因此就可以返回各自不同的数值了。

function(num){
    return function(){
        return num;
   }
}(i);
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

闭包是JS中一个比较重要的概念,对于初学者来说,可能也是较为难以理解的知识点,希望本文来带给大家一点帮助。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值