js闭包详解

  今天在写代码之余看了下js闭包,相对于之前的理解又有了稍微深入点的理解。在此分享下我的理解:

本文总共分为五个大的部分:1.理解js闭包前需要理解的js其他慨念。2.js闭包的特性。3.闭包举例。4.使用js闭包的好处。5.js闭包的用途。6.优化我的js代码。

  1:理解js闭包前需要理解的js其他慨念

   a:js的作用域链

js作用域链:作用域链是js函数在创建的时候定义的,用于寻找到变量的一个索引。作用域链索引的内部规则是将函数自身的本地变量放在最前面,把自身的父级函数变量放在其次,再把高一级的函数的变量放在更后面,以此类推知道全局对象为止。当需要查找一个变量时,js解释器会从作用域链去查找该变量,先从该函数的本地变量开始查找,如果没有,则在下一级作用域链进行查找,如果查找到相应变量则返回该变量,如果直到最后也没找到相应变量则返回undefined。

   b:js内存回收机制

js的内存回收机制:一个函数在执行开始的时候,会给其中定义的变量划分内存空间保存,以备后面的语句所用,等到函数执行完毕返回了,这些变量就被认为是无用的了,对应的空间也就被回收了。下次再执行此函数的时候,所有的变量又回到最初的状态,重新赋值使用。但是如果这个函数内部又嵌套了另一个函数(这就是闭包了),而这个函数是有可能在外部被调用到的。并且这个内部函数又使用了外部函数的某些变量的话.这种内存回收机制就会出现问题。如果在外部函数返回后,又直接调用了内部函数,那么内部函数就无法读取到他所需要的外部函数中变量的值了。所以js解释器在遇到函数定义的时候会自动把函数和他可能使用的变量(包括本地变量和父级和祖先级函数的变量(自由变量))一起保存起来。也就是构建一个闭包,这些变量将不会被内存回收器所回收,只有当内部的函数不可能被调用以后(例如被删除了,或者没有了指针),才会销毁这个闭包,而没有任何一个闭包引用的变量才会被下一次内存回收启动时所回收。

  2:js闭包的特性

a:闭包的外层是个函数,闭包内部有函数。

b:闭包会return内部函数,闭包返回的函数内部不能有return。(如果有会结束闭包)

c:执行闭包后,闭包的内部变量会存在,闭包内部函数的内部变量会回收。

  3:js闭包举例

 

复制代码
1 function outerFun(){
2    var myVal=0;
3     function innerFun(){
4         alert(++myVal);
5     }
6     return innerFun;
7 }
8 var myFun = outerFun();
9 myFun();myFun();

复制代码

此js代码在执行的过程中分别alert出1,2。由此可知执行闭包后,闭包的内部变量会存在,闭包内部函数的内部变量会回收。

  4:使用js闭包的好处

使用闭包有以下几大好处:

a:希望一个变量长期驻扎在内存中。

b:避免全局变量的污染。

 

复制代码
var abc = (function(){   //abc为外部匿名函数的返回值
    var a = 1;
    return function(){
        a++;
        alert(a);
    }
})();
abc();  //2 ;调用一次abc函数,其实是调用里面内部函数的返回值  
abc();  //3
复制代码

 

c:私有成员的存在。

复制代码
var aaa = (function(){
    var a = 1;
    function bbb(){
        a++;
        alert(a);
    }
    function ccc(){
        a++;
        alert(a);
    }
    return {
        b:bbb,       //json结构
        c:ccc
    }
})();
aaa.b();   //2
aaa.c()   //3
复制代码

 

  5:js闭包的用途

a:匿名自执行函数。

 

(function(){    
    alert("已进入就执行");
})();

我们创建了一个匿名的函数,并立即执行它,由于外部无法引用它内部的变量,因此在执行完后很快就会被释放,关键是这种机制不会污染全局对象。

b:使用闭包对数据进行缓存。

在我们做项目的时候,经常遇到一些数据非常大且没有必要进行及时查询的数据。如下拉框数据等。那么在此时我们可以在启动应用的时候在页面将这些数据进行缓存起来,如果缓存中有我们需要的数据则直接读缓存,如果缓存中没有我们需要的数据,则进行查询数据库。闭包可以为我们做到这点。

 

复制代码
var CachedSearchData = (function () {
        var cacheData = [], count = cacheData.length;
        return {
            getSearchData: function (id) {
                if (id in cacheData) {//如果结果在缓存中
                    return cacheData[id];//直接返回缓存中的对象
                } else {
                    //到数据库中查找
                    alert("search in database");
                }
            },

            clearSearchData: function (id) {
                if (dsid in cache) {
                    cache[dsid].clearSelection();
                }
            }
        };
    })();

    CachedSearchData.getSearchData(77);
复制代码

 

  6:优化我的js代码

在以后的js代码中可使用闭包进行优化一些代码。

复制代码
var person = function(){    
    //变量作用域为函数内部,外部无法访问    
    var name = "default";       
       
    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
}();    
     
alert(person.name);//直接访问,结果为undefined    
alert(person.getName());    
person.setName("zhangsan");    
alert(person.getName());

发表评论

电子邮件地址不会被公开。 必填项已用*标注