官方的解释能够无视了,比绕口令还要绕口令的拗口的词汇拼接。
我的理解就是在函数中嵌套函数。javascript
理解闭包必须先理解另外另个内容:1.做用域链 2.垃圾回收html
js中有两种变量,一种叫局部变量,一种叫全局变量。java
没有写在function内部的都是全局变量,写在function内部的都是局部变量,为了不本身定义的变量名污染全局变量名(尤为是如今调用的js控件愈来愈多的年代),所以不多会定义全局变量。数组
由于局部变量就是声明在function内部的变量,所以这个function就是该变量的做用域。也就是这个function内部,包括这个function的儿子(子函数)、孙子(子函数内的子函数),都可以访问到。这也就是说,这个function内部的子函数也能够访问到这个变量。闭包
var f = function(){ // f就是a的做用域 var a = 999; function f1(){ // 所以,即便在f的内部嵌套函数(子函数)中也能够访问到a alert(a); } f1(); }; f();
在函数执行的时候,js的解释器会给全部须要用到的变量分配一个内存空间,这样一直到这个函数执行结束,就会认为这些变量已经没有用了,就会启用垃圾回收机制来把这些内存回收。函数
这样在遇到函数嵌套时,如上面例子所示,在f执行完成以后,变量a由于还要被f1这个内部嵌套函数继续使用,所以a并不会被释放,所以,在f1()的结果是999
也就是说,在js解析器发现函数中嵌套了函数时,就会把函数中的变量和子函数中的变量一块儿保存在内存中,也就是构建了一个“闭包”。这些变量不会被内存回收器回收,只有当内部嵌套函数再也不执行以后,才会被回收。优化
var person = function(){ var name = "张三"; this.getName=function(){ return name; }; }; var p = new person(); alert(p.getName());
上面的代码里,name这个属性只能经过调用getName这个方法才能获取,这是必包的用法之一。this
经典案例:code
html: <ul> <li>aaa</li> <li>bbb</li> <li>ccc</li> <li>ddd</li>
想要实现的效果是点击li的时候,alert各自的内容,
好比点击第一个,alert “aaa”
不少人第一反应的代码以下:htm
var foo = function(){ var lis = document.getElementsByTagName("li"); for (var i= 0;i<lis.length;i++){ lis[i].onclick = function(){ alert(i); }; } }; foo();
而后会发现结果和想象中彻底不同,点击任何一个都是返回4。
这是由于在赋值的时候,传的i是对内存地址对引用。当循环结束后,i指向对就是4.所以,全部的li在点击时都是alert(4)。
在这个时候就要用到闭包了。在每一次循环的时候,都把当前的i经过当即执行函数赋值。
以下所示:
<script type="text/javascript"> "use strict" var foo = function(){ var liList = document.getElementsByTagName("li"), i=0, max = liList.length; for(;i<max;i++){ (function(index){ liList[index].onclick = function(){ alert(liList[index].innerHTML); }; })(i); } }; foo(); </script>
话很少说,直接上代码
var fibonacci = function(n){ // 将斐波那契数列放在这个临时变量中 var arr = [0,1,1]; var fi = function(m){ // 若是存在则直接返回 if(arr[m]){ return arr[m]; }else { // 若是不存在则递归获取 arr[m] = fi(m-1)+fi(m-2); return arr[m]; } }; return fi(n); }; alert(fibonacci(10));
上面的代码若是不用闭包来作,那么arr数组将不能一直保存在内存中,每次递归都会重置了。
固然,以上代码能够进一步优化:
var fibonacci = (function(){ var arr = [0,1,1]; return function(n){ if(arr[n]){ return arr[n]; } else { arr[n] = fibonacci(n-1)+fibonacci(n-2); return arr[n]; } }; })();
内部嵌套函数返回这样一个匿名函数:
function(n){ if(arr[n]){ return arr[n]; } else { arr[n] = fibonacci(n-1)+fibonacci(n-2); return arr[n]; } }
所以主函数要当即执行才能返回结果。
<script type="text/javascript"> "use strict" var btns = document.getElementsByTagName("button"), i=0, btnLength = btns.length; for(;i<btnLength;i++){ (function(k){ btns[i].onclick = function(){ this.innerHTML = "哈哈"; for(var j=0; j<btnLength;j++){ if(k!=j){ btns[j].innerHTML = "呜呜"; } } }; })(i); } </script>
上面这种写法虽然可行,可是每次点击都要循环12次,效率过低,能够进一步使用闭包。
<script type="text/javascript"> "use strict" var load = function(){ var btns = document.getElementsByTagName("button"), i=0, btnLength = btns.length, current; for(;i<btnLength;i++){ (function(k){ btns[i].onclick = function(){ if(current){ current.innerHTML = "呜呜"; } this.innerHTML = "哈哈"; current = this; }; })(i); } }; window.onload = load(); </script>
这样写简直太巧妙了。。。 先在闭包中建立current这个变量,而后若是current存在,则说明这不是第一次点击了,那么current中保存的就是上一次点击的那个按钮。因此只要把上一次点击的按钮变回“呜呜”便可。 而后再把此次的先变为哈哈,再存到current中。