当在函数中声明一个变量的时候,如果该变量前面没有带上关键字 var,这个变量就会成为全局变量 ,这当然是一种很容易造成命名冲突的做法。 另外一种情况是用 var 关键字在函数中声明变量,这时候的变量即是局部变量,只有在该函数内部才能访问到这个变量,在函数外面是访问不到的。
例:变量的搜索是从内到外而非从外到 内的
var a=1; var func1 = function(){ var b=2; var func2 = function(){ var c=3; console.log ( b ); // 输出:2 console.log ( a );// 输出:1 } func2(); console.log(c);//输出:Uncaught ReferenceError: c is not defined }; func1();
var func = function(){ var a=1; returnfunction(){ a++; console.log(a); } }; var f=func(); f();// 输出:2 f();// 输出:3 f();// 输出:4 f();// 输出:5
跟我们之前的结论相反,上面的例子在当退出函数后,局部变量 a 并没有消失,而是似乎一直在某个地方 存活着。这是因为当执行 var f = func();时,f 返回了一个名函数的引用,它可以问到 func() 被调用时产生的环境,而局部变量 a 一直处在这个环境里。既然外局部变量所在的环境还能被外 界访问,这个局部变量就有了不被销毁的理由。在这里生了一个闭包结构,局部变量的声明看起来被延续了。
例二,假设页面上有 5 个 div 节点,我们通过循环来给每个 div绑定 onclick 事件,按照索引顺序,点击第 1 个 div 时弹出 0,点击第 2 个 div 时出 1,以此类
var nodes = document.getElementsByTagName( 'div' ); for(var i=0,len=nodes.length;i<len;i++){ nodes[ i ].onclick = function(){ alert(i); } };
测试这段代码会发现,无论点击哪个 div,最后弹出的结果都是 5
这是因为 div 节点的 onclick 事件是被异步触发的,当事件被触发的时候,for循环早已结束,此时 i 的值已经是 5,
所以在 div 的 onclick 事件函数中顺着作用域链从内到外查找变量 i 时,查找到的值总是 5。
解决方法是在闭包的帮助下,每次循环的 i 值都封闭起来。当在事件函数中顺着作用域链从内到外查找变量 i 时,会先找到被封闭在闭包环境中的 i,如果有5个div,这里的i分别 是 0,1,2,3,4
for(var i=0,len=nodes.length;i<len;i++){ (function( i ){ nodes[ i ].onclick = function(){ console.log(i); } })(i) };
三、闭包的作用
1、封装变量—-闭包可以帮助一些不需要暴露在全局的变量封装成“私有变量”
例一,计算乘积
var mult = function(){ var a=1; for(var i=0,l=arguments.length;i<l;i++){ a = a * arguments[i]; } return a; };
2、延续局部变量的寿命
四、闭包与内存泄漏
functiona() { var i = 0;
functionb() { console.log(++i); } return b; } var c = a(); c();