前端-后端学习之路

CSDN博客体验不好,我的博客更新在:https://zrysmt.github.io/

【javascript】理解闭包(Closure)

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

1.快速开始

这样所确实不好理解,现在举一个简单的例子,快速入门。

function a(){
    var i=0;
    function b(){
        alert(++i);
    }
    return b;
}

var c=a();
c();//1

这样在执行完var c=a( )后,变量c实际上是指向了函数b,再执行c( )后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:
当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。


这个时候我们仍然不太清楚怎么回事。现在我们先不看原理,直接过来看看它的作用。

2.闭包的作用

一句话:闭包的活动对象(变量)会常驻内存
a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量

3.闭包的原理

这部分是最复杂的,先举一个例子来提出来几个概念。

参考 Javascript高级程序设计(第三版)

function compare(value1, value2){
    if (value1 < value2){
        return -1;
    } else if (value1 > value2){
        return 1;
    } else {
        return 0;
    }
}
var result = compare(5, 10);

当调用compare()时,会创建一个包含arguments、value1 和value2 的活动对象。全局执行环境的变量对象(包含result和compare)在compare()执行环境的作用域链中则处于第二位。
这里写图片描述
概念:
执行环境:当调用compare()函数的时候,会为函数创建一个执行环境,通过复制函数的[[Scope]]属性中的对象建立作用域链
作用域链:作用域链本质上是一个指向变量对象的指针列表,它只
引用但不实际包含变量对象。包含:全局变量的对象和compare()的活动对象。
一般来讲,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象)。
但是,闭包又有所不同:

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

当createComparisonFunction()函数返回后,其执行环境的作用域链会被销毁,但它的活动对象仍然会留在内存中(匿名函数的作用域链仍然在引用这个活动对象);直到匿名函数被销毁后,createComparisonFunction()的活动对象才会
被销毁

//创建函数
var compareNames = createComparisonFunction("name");
//调用函数
var result = compareNames({ name: "Nicholas" }, { name: "Greg" });
//解除对匿名函数的引用(以便释放内存)
compareNames = null;

闭包

4.闭包的用途

参考 http://blog.csdn.net/sunlylorn/article/details/6534610

4.1 匿名自执行函数

例子:UI初始化,只需要执行一次,其内部变量无需维护

var datamodel = {    
    table : [],    
    tree : {}    
};    

(function(dm){    
    for(var i = 0; i < dm.table.rows; i++){    
       var row = dm.table.rows[i];    
       for(var j = 0; j < row.cells; i++){    
           drawCell(i, j);    
       }    
    }    

    //build dm.tree      
})(datamodel); 

4.2 缓存

var CachedSearchBox = (function(){    
    var cache = {},    
       count = [];    
    return {    
       attachSearchBox : function(dsid){    
           if(dsid in cache){//如果结果在缓存中    
              return cache[dsid];//直接返回缓存中的对象    
           }    
           var fsb = new uikit.webctrl.SearchBox(dsid);//新建    
           cache[dsid] = fsb;//更新缓存    
           if(count.length > 100){//保正缓存的大小<=100    
              delete cache[count.shift()];    
           }    
           return fsb;          
       },    

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

CachedSearchBox.attachSearchBox("input1"); 

这样,当我们第二次调用CachedSearchBox.attachSerachBox(“input1”)的时候,
我们就可以从缓存中取道该对象,而不用再去创建一个新的searchbox对象。

4.3 实现封装

var person = function(){    
    //变量作用域为函数内部,外部无法访问    
    var name = "default";       

    return {    
       getName : function(){    
           return name;    
       },    
       setName : function(newName){    
           name = newName;    
       }    
    }    
}();    

print(person.name);//直接访问,结果为undefined    
print(person.getName());    
person.setName("abruzzi");    
print(person.getName());    

得到结果如下:  

undefined  
default  
abruzzi  
阅读更多
版权声明:本文为博主原创文章,转载请注明出处和原文链接。 https://blog.csdn.net/future_todo/article/details/49928607
文章标签: javascript 闭包
个人分类: javascript读书笔记
上一篇【PHP】找几个例子就能快速复习PHP基础知识
下一篇【数据科学】《微软亚洲研究院大数据系列讲座》1-大数据研究现状及未来趋势
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭