概念:当一个内部函数被调用,就会形成闭包,闭包就是能够读取其他函数内部变量的函数
就是一个函数去访问了另外一个函数的中的变量的函数
例子:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>闭包</title> </head> <body> <script type="text/javascript"> //允许函数中嵌套函数 //内部函数允许调用外部函数的变量 //闭包就是能够读取其他函数内部变量的函数,内部函数和执行的上下文 var foo=function(){ var n=1; return function(){ n=n+1; console.log(n); } } var bar=foo(); bar(); //2 bar(); //3 var foobar=foo(); foobar(); //2 foobar(); //3 </script> </body> </html>
运行结果:
闭包作用:局部变量无法共享和长久的保存,而全局变量可能造成变量污染,所以我们希望有一种机制既可以长久的保存变量又不会造成全局污染。延伸变量的作用范围。
闭包特点:占用更多内存;不容易被释放
闭包用法:变量既想反复使用,又想避免全局污染如何使用?
1.定义外层函数,封装被保护的局部变量。
2.定义内层函数,执行对外部函数变量的操作。
3.外层函数返回内层函数的对象,并且外层函数被调用,结果保存在一个全局的变量中。
例子:
function getCounter() { var n = 1; var inner = function () { return n++; } return inner; } var getNum = getCounter(); getNum(); // n = 2; /*// 类似于 var n = 1; var getNum = function () { return n++; } getNum(); // n = 2; // 当调用getNum 就获取到了n的值*/
实用例子:看下面代码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>闭包</title> </head> <button>按钮1</button> <button>按钮2</button> <button>按钮3</button> <button>按钮4</button> <button>按钮5</button> <button>按钮6</button> <button>按钮7</button> <button>按钮8</button> <button>按钮9</button> <body> <script type="text/javascript"> // 闭包的作用 var btn = document.querySelectorAll('button'); for (var i = 0; i < btn.length; i++) { btn[i].onclick = function() { alert(i); } } </script> </body> </html>
结果是,点击任何按钮都是弹出9,和我们预想的结果点击按钮1输出0,按钮3输出2,的不一样。
因为我们的function是一个一部任务,只有点击了才会执行,当循环结束了,i就等于4了,所以点击按钮,执行function但是已经等于4了。
解决方法:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>闭包</title> </head> <button>按钮1</button> <button>按钮2</button> <button>按钮3</button> <button>按钮4</button> <button>按钮5</button> <button>按钮6</button> <button>按钮7</button> <button>按钮8</button> <button>按钮9</button> <body> <script type="text/javascript"> // 闭包的作用 var btn = document.querySelectorAll('button'); for (var i = 0; i < btn.length; i++) { btn[i].index = i; btn[i].onclick = function() { alert(this.index); } } </script> </body> </html>
给每个btn都绑定一个index属性,并把i赋值给index,当点击了再获取。
当然也可以使用闭包来解决这个问题
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>闭包</title> </head> <button>按钮1</button> <button>按钮2</button> <button>按钮3</button> <button>按钮4</button> <button>按钮5</button> <button>按钮6</button> <button>按钮7</button> <button>按钮8</button> <button>按钮9</button> <body> <script type="text/javascript"> // 闭包的作用 var btn = document.querySelectorAll('button'); for (var i = 0; i < btn.length; i++) { (function (a) { btn[i].onclick = function() { alert(a); } })(i); } </script> </body> </html>
这里面写了一个立即执行函数,把i的值传入到立即执行函数里面,那么立即执行表达函数就有了一个变量
// 闭包的作用 var btn = document.querySelectorAll('button'); for (var i = 0; i < btn.length; i++) { // 立即执行表达函数 (function (a) { // 这里是一个function,其中有个变量a btn[i].onclick = function() { // 这里也是一个function alert(a); } })(i); // 把i传入立即执行函数 }
实用案例2:
var btn = document.querySelectorAll('button'); for (var i = 0; i < btn.length; i++) { setTimeout(function() { console.log(btn[i].innerHTML); }, 3000) }
for循环是一个同步任务,会立马执行,但是setTimeout是一个异步的,里面的function是一个回调函数,只有执行了setTimeout才会执行这个function,所以我执行这个setTimeout的时候 i 变成了9,我只有8个元素,所以出错了。
使用闭包:
var btn = document.querySelectorAll('button'); for (var i = 0; i < btn.length; i++) { (function(a) { setTimeout(function() { console.log(btn[a].innerHTML); }, 3000); })(i); }