想要学习闭包先来看看什么是匿名函数吧!
(一)匿名函数
匿名函数就是没有名字的函数。他有两种声明方式:
1.典型的函数声明: function functionName(arg0,arg1,arg2){ //函数体 } 2.函数表达式: var functionName = function(arg0,arg1,arg2){ //函数体 } 虽然这两种方式在逻辑上市等价的,可是他们仍是存在区别的。 区别1:前者会在代码执行之前被加载到做用域中,然后者则是在代码执行到那一行的时候才会有意义。 区别2:前者会给函数指定一个名字,然后者则是建立一个匿名函数,而后将这个匿名函数赋给一个变量。 换句话说上面第二个例子:建立了一个带有3个参数的匿名函数,而后把这个匿名函数赋给了变量functionName,并无给匿名函数指定名字。 (二)闭包 书上定义是这么说的:指有权访问另外一个函数做用域中的变量的函数 但是这种说法令新手难以理解。其实,在本质上,闭包就是将函数内部和函数外部链接起来的一座桥梁。 1.那我先来讲说为何要有闭包这么个概念吧,它产生的意义是什么呢? (1)首先咱们学过前面的做用域了,知道了一个概念:函数内部能够直接读取全局变量。 那么看代码: var n=999; function f1(){ alert(n); } f1(); // 999 (2)而后另一个概念:在函数外部天然没法读取函数内的局部变量 那么再看代码: function f1(){ var n=999; } alert(n); //输出错误 (3)这里有一个地方须要注意,函数内部声明变量的时候,必定要使用var命令。若是不用的话,你实际上声明了一个全局变量!(咱们之前也提到过的!) function f1(){ n=999; } f1(); alert(n); // 999 下面关键的来了!:那就是如何从外部读取局部变量呢? 那就是在函数的内部,再定义一个函数。(也就是闭包!!) function f1(){ var n=999; function f2(){ alert(n); // 999 } } 在上面的代码中,函数f2就被包括在函数f1内部,这时f1内部的全部局部变量,对f2都是可见的。可是反过来就不行,f2内部的局部变量,对f1就是不可见的。既然f2能够读取f1中的局部变量,那么只要把f2做为返回值,咱们不就能够在f1外部读取它的内部变量了吗!来看代码: function f1(){ var n=999; function f2(){ alert(n); } return f2; } var result = f1(); result(); //999 这段代码与上面的不一样点就是把f2函数做为了一个返回值,而后在调用它。这时你确定在想最后两行什么意思啊?其实开始我也没闹明白,通过高人指点,其实这最后两行的意思就是要调用f2这个函数的返回值。这两行若是我改写一下是否是更容易明白了呢? var result = f1(); result(); 合并成为:f1()();其实结果是同样的 也能够更好的说明f2这个闭包的做用是:经过把它做为返回值(由于它能访问函数f1内的局部变量),而后从全局环境中调用这个返回值,这样天然就达到了咱们的目的---从全局做用域中读取局部函数内的变量! 2.既然知道了闭包的意义,下面就来了解下闭包的用途吧! (1)闭包的第一个用途,其实上面已经提到了,就是产生它意义:能够读取函数内部的变量 (2)闭包的第二个用途,那就是:可让这些变量的值始终保持在内存中 第二个用途怎么理解呢?来看代码: function f1(){ var n=999; nAdd=function(){ n+=1 } function f2(){ alert(n); } return f2; } var result=f1(); //把f1函数的返回值(而这个返回值是函数f2的形式)给result result(); // 999 输出这个f2的返回值 nAdd(); //调用nAdd函数 result(); // 1000 这里就是闭包的第二个用途:f2这个闭包会让变量n的值始终保存在内存中 光靠代码来理解第二种用途,好像没有什么说服力,下面就用画图的方法来让你们更深入的理解!! 第二种用途其实就和做用域链产生联系了,我来解释下: 闭包f2从f1函数中被返回后,它的做用域链被初始化为包含f1函数的活动对象和全局变量对象(黑线部分)。这样f2就能够访问在f1()函数中定义的全部变量。更为重要的是就算f1()被执行完毕后,它的活动对象也不会被销毁,由于如图f2这个闭包还在引用f1函数的活动对象,这也就是为何上述第二种用途的缘由:闭包会让变量始终保存在内存中,直到闭包被摧毁。