现在的位置: 首页 > 综合 > 正文

【深入JavaScript】2.闭包(读书笔记)

2013年03月13日 ⁄ 综合 ⁄ 共 2020字 ⁄ 字号 评论关闭

读《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基础书真心好,闭包这部分得多看看。

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

  共勉。

抱歉!评论已关闭.