闭包之我的理解

闭包是javascript的一个难点,也是一个重点,很多高级应用都需要用到闭包。在学习闭包的过程中看了不少书和大牛的博客,下面来说说我对闭包的理解和看法。

函数

要说闭包就不得不先说一下函数,这个javascript的中流砥柱。
众所周知在ES6之前js都没有class这个关键字,一切的面向对象都是通过function模拟的。

一个简单到不能再简单的例子:函数内部可以访问外部的变量(全局变量)。

var n=100;
function f1()
{
    console.log(n);
}
f1();//100

而外部却不能访问函数内的局部变量。

function f1()
{
    var n=100;
}
console.log(n);//n is not defined

那么问题来了,如果我想访问函数内的局部变量怎么办?一种解决办法就是使用闭包。
什么是闭包?我个人认为函数中的函数就是闭包,有点像java的内部类,既然函数可以访问外部变量,那么函数中的函数也可以访问外层函数的变量,这个内层函数就是闭包。

function f1()
{
    var n=100;
    function f2()
    {
        console.log(n);
    }
    f2();
}
f1();//100

上述写法比较麻烦,因此可以把f2作为一个返回值返回给f1。

function f1()
{
    var n=100;
    function f2()
    {
        console.log(n);
    }
    return f2;
}
f1()();//100
//相当于var f=f1();f();

下面来看一个问题:这里有5个li,名字是0到4,我希望我点击0的时候在控制台输出0,点击1的时候在控制台输出1,以此类推。

var lis=document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++)
{
    lis[i].onclick=function()
    {
        console.log(i);
    }
}

奇怪的事情发生了,无论我点击哪一个在控制台输出的都是5。
这是为什么呢?
仔细观察,我为每个li创建了一个匿名函数,匿名函数形成了闭包,它们都在引用外部的i,当i改变时,自然所有匿名函数里面的i都改变了。用几张图来说明。




当i增加到5的时候不再满足循环条件,由于五个匿名函数都是引用同一个i,所以它们打印出来的都是5。

既然它们是引用同一个i,那么只需为每一个i创建一个备份:

var lis=document.getElementsByTagName("li");
for(var i=0;i<lis.length;i++)
{
    lis[i].onclick=function(num)
    {
        return function()
        {
            console.log(num);
        }
    }(i)
}

这里在匿名函数接收一个参数并且立即执行,匿名函数内部又创建了一个函数负责把这个参数返回给匿名函数,由于是按值传递的,所以相当于给i做了一个备份。就算i一直在改变,而每个匿名函数的num是固定的。

闭包中的this

在闭包中使用this会出现一些问题,在全局函数中this指向的是window,当函数以方法被调用时,this就指向这个对象。但是,匿名函数的执行环境具有全局性,this一般指向window。参考红宝石书中的一个经典的问题:

var name="The Window";
var object={
    name:"My Object",
    getNameFunc:function(){
        return function(){
           return this.name;
        };
    }
};
alert(object.getNameFunc()());//"The Window"

内部函数在搜索this的时候只会搜到其活动对象为止,由于匿名函数的执行环境具有全局性,因此当前的活动对象就是window。

可以通过改变当前的活动对象来改变this的指向:

var name="The Window";
var object={
    name:"My Object",
    getNameFunc:function(){
        var that=this;
        return function(){
            return that.name;
        };
    }
};
alert(object.getNameFunc()());//"My Object"

这里把this对象赋值给了一个that变量,因此当前的活动对象就从window变成了object。

闭包引发的问题

闭包虽好,但是也引发了一系列问题,尤其是内存泄漏。js的垃圾回收机制是引用计数的,当一个变量不再使用的时候(引用计数为0)垃圾回收机制就会把它清理掉。而闭包的存在会导致引用数至少为1。

function f()
{
   var myDiv=document.getElementById("Div1");
   myDiv.onclick=function()
   {
        console.log(myDiv.id);
   };
}

上述代码中,函数f需要等myDiv清除后才能被清除,而myDiv由于匿名函数的存在,它的引用数至少为1,因此它所占用的内存永远不会被回收。

解决办法:

function f()
{
   var myDiv=document.getElementById("Div1");
   var id=myDiv.id
   myDiv.onclick=function()
   {
        console.log(id);
   };
   myDiv=null;
}

把myDiv.id保存在一个变量中,并且在闭包中引用这个变量,这样就与myDiv没有关系了。但是闭包会引用包含函数的整个活动对象,因此必须把myDiv设为null来解除对它的引用,确保垃圾回收机制能够把资源回收。

使用闭包应该注意的问题:闭包虽然好,但是在实际应用中尽量减少 闭包的使用,并且为了防止内存泄漏,要时刻记得在闭包完后清除它的局部变量。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容