作用域链【深入JavaScript】2.闭包(读书笔记)

最近朋友几篇文章介绍了改作用域链的文章. 关联文章的地址

    读《JavaScript高等程序设计》第7章有感。

    

一、究竟闭包是什么?

     闭包是指有权拜访另一个函数作用域中的变量的函数。

     个人感悟:

     通过书中的这句定义,按中文语法分析,说白了,闭包就是一种函数,而这种函数可以拜访另一个函数作用域中的变量。

     那为什么这种函数有这样牛B的功能呢?其实,它是利用了函数的作用域链。

     

    

二、创建闭包的罕见方式:在一个函数外部创建另一个函数

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;

    }

  };
} 
留意这个例子中标红的地方。标红处是一个外部函数的代码,而这个外部函数正是匿名函数。

     这两行代码拜访了外部函数中的变量propertyName。即使这个外部函数被返回了,而且是在其他地方被调用了,但它仍然可以拜访变量propertyName。

     之所以还可以拜访这个变量,是因为这个匿名函数的作用域链中包含了createComparisonFunction()的作用域(在作用域链中是以变量对象表示)

 

    

三、闭包可以起什么作用?为什么闭包可以起作用?

     说到这里,我们不得不回忆一下之前学过的关于作用域链的知识。只有透彻懂得作用域链,才能真正懂得闭包起什么作用,为什么可以起作用

     关于作用域链的知识,在我上一篇博文中已详细说明,在这就不重复叙说了,我只讲症结的地方。

     首先,当调用某个函数的时候,系统会为函数创建一个执行环境,并且通过复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链。而函数的活动对象作为变量对象被推入执行环境作用域链的最前端。

     可见,当函数被调用时,会创建两个货色,一个是函数的执行环境,另一个则是其相应的作用域链

     一般来说,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域(也就是全局执行环境的变量对象)。

     但是,闭包的情况有所不同。原因就是:

 

     在另一个函数外部定义的函数会将包含函数(即外部函数)的活动对象添加到它的作用域链中。

      

     回到下面的例子:

    每日一道理
记不清有多少个夜晚,在我翻阅纸张的指间滑落;记不清有多少支蜡烛,在我的凝视中化为灰烬。逝者如斯,我时时刻刻会听见自己对生命承诺的余音,感到岁月的流转在渐渐稀释我的年少无知,我愿自己是一只上足了发条的时钟,在昼夜不停的流转中留下自己充实的每一刻。
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()的活动对象。

     在匿名函数从createComparisonFunction()中被返回后,它的作用域链就变成了下图所示:

    作用域和链

     此时,匿名函数可以拜访在createComparisonFunction()中定义的所有变量。

     更重要的是,当createComparisonFunction()函数执行完毕后,也就是返回了匿名函数后,它的活动对象也不会被销毁,这是因为匿名函数的作用域链仍然在引用这个活动对象

     也就是说,当createComparisonFunction()函数返回后,它的执行环境的作用域链会被销毁,但它的活动对象仍然被引用。根据JS的GC策略,因为该活动对象引用次数不为0,因此它会留在内存中,直到匿名函数被销毁后,createComparisonFunction()的活动对象才会被销毁。

 

    

四、闭包与变量

     由上知,闭包是通过作用域链这种机制来实现的,因此,它也有着一个值得我们注意的副作用,那就是:

     闭包只能获得包含函数中任何变量的最后一个值,因为闭包只是引用其作用域链上的变量对象。

     例子不敲了,自己推敲一下吧哈~书上有,懒得敲了。

 

    

五、总结

     由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存,过度应用闭包可能会致使内存占用过多,这方面要注意一下。

     这本JS基本书至心好,闭包这部分得多看看。

     关于闭包的一些应用将在下一篇文章报告。

     共勉。

文章结束给大家分享下程序员的一些笑话语录: 有一天,一个男人穿越森林的时候,听到一个细微的声音叫住他。他低头一看,是一只青蛙。
“如果你亲我一下,我会变成一个美丽的公主哦。”男人一言不发,把青蛙捡起来,放入口袋。
“如果你亲我一下,我会变成一个美丽的公主哦。而且,我会告诉我遇到的每一个人,你是多么聪明和勇敢,你是我的英雄。”男人把青蛙拿出来,对着它微微一笑,又把它放回口袋。
“如果你亲我一下,我会变成一个美丽的公主,然后我愿意成为你的爱人一星期。”男人又把青蛙拿出来,对着它微微一笑,把它放回口袋。
“如果你亲我一下,我会变成一个美丽的公主,然后我愿意成为你的爱人一年,而且你可以对我做任何事。”再一次,男人把青蛙拿出来,对着它微微一笑,又把它放回口袋。
  最后,青蛙无力地问:“我开出了这么好的条件,为什么你还不肯吻我?”男人说:“我是一个程序员,我可没时间和什么公主鬼混。不过,拥有一个会说话的青蛙,倒是蛮酷的。”


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值