JavaScript之闭包详解

前言:

    闭包是Javascript语言的一个难点,也是它的特色,很多高级的应用都要依靠闭包来实现。之前看李炎恢老师虽然讲的特别的好,当时理解的并不是很深刻,今天通过实例来更好的解释什么是闭包,希望看后的朋友能够理解。

    本篇文章分三部分来讲解闭包,首先说变量的作用域,然后说内部函数,和如何从外部读取局部变量,最后引入我们今天的主题——闭包。这篇文章用到的例子比较多,希望认真阅读,最后敲例子更能充分理解

一、变量的作用域                                                       

   要理解闭包,首先必须理解Javascript特殊的变量作用域。
   在JavaScript中,变量的作用域分两种:全局变量和局部变量。
   在Javascript中,在函数内部可以直接读取全局变量。

var n=123;//定义全局变量n
 function f1(){
  alert("在函数内部访问全局变量n,n="+n);//在函数内部访问全局变量n
}
运行结果:

JavaScript之闭包详解_第1张图片
但反过来不行,在函数的外部无法读取函数内的局部变量

function f1(){
   var n=123;//在f1函数内部定义局部变量n
 }
alert("在函数外部访问局部变量n,n="+n); //在函数外部访问局部变量n,错误:n未定义

需要注意的是,函数内部声明变量的时候,一定要使用var命令。如果不用的话,实际上是声明了一个全局变量!

二、内部函数                                                           

首先来看一个实例:

function A(){
    function B(){            //B就是一个内部函数
        alert("你好!");
    }
}
由于函数B在函数A的内部,因此B函数在函数A内有效,但是在外部调用时无效的,如:
window.onload = B();  //外部调用无效

function A(){
    alert("你好");
    function B(){            //B就是一个内部函数
        alert("你好!");
    }
}                           //报错误 B is not defined
但是在内部调用是正确的

window.onload = A();

function A(){
    function B(){
        alert("你好!");
    }
    B();        //内部调用A()是正确的
}

javascript运行时需要跟踪引用这个内部函数的所有变量,直到最后一个变量废弃,javascript垃圾收集器才能释放内部函数的内存空间。也就是说,只要存在调用内部函数的可能,javascript就要保留被引用的函数。

三、如何从外部读取局部变量                                             

 在来看一个实例:

 

 function f1(){
	  var n=123;//f1函数内部的局部变量n
          //在f1函数内部定义一个f2函数
   function f2(){
        //在f2函数内部是可以访问局部变量n的
    alert(n); // 123
   }
 }
在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1 就是不可见的。这就是Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。既然f2可以读取f1中的局部变量,那么只要把f2作为返回值,JavaScript中的函数名本身就是变量,所以函数也可以当作普通变量来使用。也就是说,不仅可以像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的返回值返回。

function f1(){
    var n=123;//局部变量n
    //在f1函数内部声明的f2函数
    function f2(){
      alert(n);
    }

    return f2;//将f2函数作为f1函数的返回值
  }
  var result=f1();//f1调用完后的返回值是一个f2函数,此时result就是f2函数
  result(); // 123,调用f2函数

看了上面的实例我想应该对闭包的组成有了一定的了解,那么我们来说一下闭包

四、闭包的概念                                                         

    在看视频中,闭包:是指有权访问另一个函数作用域中的变量的函数,创建闭包的常见方式,就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量,由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

五、闭包的作用                                                         

(1)函数外部访问函数内部的函数或变量;
(2)常驻内存;

实例:

function f1(){
    var n=999;
    nAdd=function()
        {
            n += 1;
        }
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000
     result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
  为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量(result),这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

六、注意                                                               

   由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存。过度使用闭包会导致性能下降,建议在分成有必要的时候才使用闭包。


小结:

     闭包就总结到这里,这次运用了大量的例子来说明闭包,希望阅读的朋友能够看懂。

你可能感兴趣的:(JavaScript之闭包详解)