JavaScript 闭包
这很6!!!
计数器困境
设想下如果你想统计一些数值,且该计数器在所有函数中都是可用的。
你可以使用全局变量,函数设置计数器递增:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>菜鸟教程(runoob.com)</title> 6 </head> 7 <body> 8 9 <p>全局变量计数。</p> 10 <button type="button" onclick="myFunction()">计数!</button> 11 <p id="demo">0</p> 12 <script> 13 var counter = 0; 14 function add() { 15 return counter += 1; 16 } 17 function myFunction(){ 18 document.getElementById("demo").innerHTML = add(); 19 } 20 </script> 21 22 </body> 23 </html>
每次递增1!
计数器数值在执行 add() 函数时发生变化。
但问题来了,页面上的任何脚本都能改变计数器,即便没有调用 add() 函数。
如果我在函数内声明计数器,如果没有调用函数将无法修改计数器的值:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>菜鸟教程(runoob.com)</title> 6 </head> 7 <body> 8 9 <p>局部变量计数。</p> 10 <button type="button" onclick="myFunction()">计数!</button> 11 <p id="demo">0</p> 12 <script> 13 function add() { 14 var counter = 0; 15 return counter += 1; 16 } 17 function myFunction(){ 18 document.getElementById("demo").innerHTML = add(); 19 } 20 </script> 21 22 </body> 23 </html>
每次都是1!
以上代码将无法正确输出,每次我调用 add() 函数,计数器都会设置为 1。
JavaScript 内嵌函数可以解决该问题。
JavaScript 内嵌函数
所有函数都能访问全局变量。
实际上,在 JavaScript 中,所有函数都能访问它们上一层的作用域。
JavaScript 支持嵌套函数。嵌套函数可以访问上一层的函数变量。
该实例中,内嵌函数 plus() 可以访问父函数的 counter 变量:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>菜鸟教程(runoob.com)</title> 6 </head> 7 <body> 8 9 <p>局部变量计数。</p> 10 <p id="demo">0</p> 11 <script> 12 document.getElementById("demo").innerHTML = add(); 13 function add() { 14 var counter = 0; 15 function plus() {counter += 1;} 16 plus(); 17 return counter; 18 } 19 </script> 20 21 </body> 22 </html>
结果是1!
如果我们能在外部访问 plus() 函数,这样就能解决计数器的困境。
我们同样需要确保 counter = 0 只执行一次。
我们需要闭包。
JavaScript 闭包
还记得函数自我调用吗?该函数会做什么?
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>菜鸟教程(runoob.com)</title> 6 </head> 7 <body> 8 9 <p>局部变量计数。</p> 10 <button type="button" onclick="myFunction()">计数!</button> 11 <p id="demo">0</p> 12 <script> 13 var add = (function () { 14 var counter = 0; 15 return function () {return counter += 1;} 16 })(); 17 function myFunction(){ 18 document.getElementById("demo").innerHTML = add(); 19 } 20 </script> 21 22 </body> 23 </html>
结果每次递增1!!
解析:
变量 add 指定了函数自我调用的返回字值。
自我调用函数只执行一次。设置计数器为 0。并返回函数表达式。
add变量可以作为一个函数使用。非常棒的部分是它可以访问函数上一层作用域的计数器。
这个叫作 JavaScript 闭包。它使得函数拥有私有变量变成可能。
计数器受匿名函数的作用域保护,只能通过 add 方法修改。
闭包是可访问上一层函数作用域里变量的函数,即便上一层函数已经关闭。 |
这写法很 6!