JS进阶系列之闭包

我对闭包的理解就是:闭包就是能够读取其他函数内部变量的函数,可以把闭包简单理解为“定义在一个函数内部的函数”。

在读了阮一峰的博客里面关于闭包的讲解之后,自己对闭包也有了一定的认识,首先在理解闭包之前必须先理解JavaScript特殊的变量作用域。
变量的作用域有两种,全局变量和局部变量。

var n = 999;
function f1(){
  alert(n);
}
f1();//999

从以上代码可以看出Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量,当然了,函数外部自然就无法读取函数内部的局部变量,那么如何从外部读取内部的局部变量呢?
假如我们在函数内部定义一个函数,如下:

function f1(){
  var n = 999;
  function f2(){
      alert(n);//999
}
}

在上面的代码中,因为函数f2包含在函数f1中,所以函数f2可以访问f1中的局部变量,那么如果我们把函数f2作为返回值,不就可以在外部读取内部的局部变量了吗,代码如下:

function f1(){
  var n = 999;
  function f2(){
      alert(n);//999
}
return f2;
}

var result = f1();
result(); //999

其实在上面的代码中,函数f2就是闭包了,这里面要谈到闭包的两个作用:第一个就是读取函数内部的变量,也就是上述代码的作用。第二个就是让这些变量的值始终保持在内存中,看了下面的代码就能理解第二个作用的意思了:

function f1(){

    var n=999;

    nAdd=function(){n+=1}

    function f2(){
      alert(n);
    }

    return f2;

  }

  var result=f1();

  result(); // 999

  nAdd();

  result(); // 1000

由于函数f2赋值给一个全局变量result,所以函数f2保存在内存中,而函数f2的父函数是f1,依赖于f1,所以f1也会保存在内存中,导致f1中的变量也保存在内存中,不会被回收,这就是闭包的第二个作用。

在阅读<>这本书时,发现了二个与闭包相关的例子程序,第一个是:

function createFunctions(){
    var result = new Array();
    for(var i = 0; i < 10; i++) {
        result[i] = function(){
           return i;
       };
   }
   return result;
}

正常来说返回的结果应该是,每个函数都返回自己的索引值,但是最终结果却是,每个函数返回的都是10。这是因为每一个函数的作用域链中都保存着createFunctions()函数的活动对象,所以它们引用的都是同一个变量i,当createFunctions()函数返回后,i的值变成10,所以每个函数都引用着保存变量i的同一个变量对象。我们可以通过创建另一个匿名函数强制让闭包的行为符合预期,如下所示:

function createFunctions(){
    var result = new Array();
    for(var i = 0; i < 10; i++) {
        result[i] = function(num){
           return  function(){
                return num;
            }
       }(i);
   }
   return result;
}

第二个是:

var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      return function(){
        return this.name;
      };

    }

  };

  alert(object.getNameFunc()());

上面代码返回的结果是 "The Window",而不是预期的 "My Object"。我们在理解这个之前,要理解方法调用和函数调用的区别。我们将最后一句话分解成一下两句话:

var first = object.getNameFunc();
var result = first();

第一句话中调用的是object对象中的getNameFunc()方法,所以此时this对象是object,但是在第二句话中,first()是属于函数调用,是在全局环境下调用的,所以this对象变成了window,所以结果相当于返回了window.name。

为什么匿名函数没有取得其包含作用域(外部作用域)的this对象呢?
每个函数被调用时,其活动对象都会自动取得两个特殊的变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。——<>

再看下面的代码:

var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
                     var that = this;//将getNameFunc()的this保存在that变量中
      return function(){
        return that.name;
      };

    }

  };

  alert(object.getNameFunc()()); //"My Object"

返回的结果就是预期的"My Object",因为可以把外部作用域中的this保存在闭包可以访问到的变量中。

你可能感兴趣的:(JS进阶系列之闭包)