一.闭包的概念
说的简单一点,一个函数在另一个函数里面定义,这个函数可以访问其父函数的成员(即父函数的局部变量),则内部函数称为闭包。
二.产生闭包的原因
1.JavaScript支持嵌套函数。
2.作用域链(子函数即嵌套函数可以引用当前作用域的变量)的存在。
三.闭包产生条件
1.只有在父函数层面内才会产生闭包。
2.子函数需要用到父函数的一些东西。
3.子函数的子函数若用到最外层函数的局部变量也会产生闭包。
四.闭包注意事项
1.子函数对父函数的局部变量的只是引用其并不是复制。2.父函数每调用一次会产生不同的闭包。3.在循环中需要注意的问题。
4.闭包的存在会使得他不会被垃圾回收机制回收,他会比其他函数占更多的内存,过渡使用闭包可能会导致内存占用过多。可能会导致浏览器崩溃的问题。
五.闭包的好处
1.减少全局变量。2.减少传递给函数的参数。3.封装。
六.闭包的使用
1.使用构造函数法和闭包机制可以达到封装的目的。
2.使用构造函数法和原型机制可以达到继承的目的。
3.使用原型机制和对象成员你可以达到多态覆盖(对象属性和对象方法)
七.关键词汇
1.在函数外声明的变量为全局变量。(用var声明的)
定义在函数外面,为全局变量,它在一个叫做"全局作用域"的区域里面。"全局作用域"只会在浏览器窗口关闭或页面刷新的时候进行关闭。
2.在函数内声明的变量为局部变量。(注:在函数内部没用var声明的也会由于变量提升变成全局变量)
定义在函数内部时叫局部变量,"局部作用域"会在函数被调用的时候创建,而在函数运行结束的时候关闭(并且里面创建的变量跟函数也会被删掉--垃圾回收机制)
3.作用域链
子函数即嵌套的函数可以引用当前作用域中的变量,这实际上是JavaScript语言中的一个结构——作用域链(Scope Chain)。
4.匿名函数
“匿名函数自执行”(function(){})(),一般执行函数是在函数名后面加括号(),这里(function(){})相当于一个表达式,我们在它后面加(); 就相当于执行了这个函数。
5.全局预处理和词法环境
预处理阶段会创建一个词法环境然后把扫描(会扫描的东西包括两个,先扫描用声明的方式创建的函数,再扫描用var定义的变量。在处理函数声明有冲突会覆盖,处理变量有冲突会忽略。)的东西存入词法环境中,在函数预处理阶段会在每调用一次就会产生一个词法环境,然后先扫描函数的参数,再扫描声明式函数再扫描var声明的变量。
以下为闭包在循环中的注意点
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <script> /*第一*/ function f(){//创建函数 var a=[];//声明一个局部数组 var i;//声明一个局部变量 for(i=0;i<3;i++){//循环遍历数组a(创建了闭包) a[i]=function (){//即为a[i]=i,且循环012 return i; } } return a;//此时返回的a后,函数f()值为a数组 } var test=f();//把a数组赋值给test alert(test[0]());//此时test为数组,故可以访问其中值 alert(test[1]()); alert(test[2]()); //以上希望弹出值为012,但其实不能,因为该处闭包对局部变量i的值只是引用,并不会记录它的值,所以引用其循环最后的值弹出为333,因为循环到3结束。 </script> </body> </html>
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <script> /*第二*/ function f(){ var a=[]; var i; for(i=0;i<3;i++){ a[i]=(function (x){//创建一个自调用函数(此处为闭包) return function (){ return x; }//i作为实参传入那么形参就可以得到i三次循环的值,而x值是闭包本身的,并不存在像i一样只能引用不能记录值的情况,所以x就可以间接得到i的循环值并保存,最后返回a[i]=x(x值为012),此时a[]数组就保存了012这三个值 })(i);//i为每次循环产生的值,此处自调用,所以将i的值(012)作为实参传入 } return a; } var test=f();//由上面可知这次弹出会是012 alert(test[0]()); alert(test[1]()); alert(test[2]()); </script> </body> </html>
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <script> /*第三*/ function f(){ function test(x){ return function (){//原因为通过中间函数将i的值本地化,把i传进函数调用该函数, //在函数体内通过闭包返回参数值来实现 return x; } } var a=[]; var i; for(i=0;i<3;i++) { a[i] = test(i); } return a; } var res=f();//此时也可以弹出012 alert(res[0]()); alert(res[1]()); alert(res[2]()); </script> </body> </html>