闭包——之初理解
闭包,是javascript中的一个概念,对于初学者很难理解抽象的概念,看了很多大牛们的解释,也是似懂非懂的,今天在知乎上看到很多“大神”们对“闭包”做了又一番解释,在其中也学到了不少,下面就来说下自己对闭包的理解吧。
闭——外面的变量看不到里面的,包——可以对内部变量操作,返回一个'包';
闭包并不是私有的,闭的意思不是封闭“内部状态”,而是封闭“外部状态” ;
用知乎上“大神”更简洁的一句话总结:闭包就是一个有记忆的函数;
在《js高级程序设计》里面的解释:闭包是指有权访问另一个函数作用域中的变量函数。
1.看一个简单的闭包的例子: |
function A(){ function B(){ console.log("Hello world!"); } return B; } var c = A(); c();//Hello world!
最常见的闭包,就是在一个函数内部再创建一个函数;也是最简单的闭包,有了上面简单的概念认识,我们分析一下闭包函数和普通函数有什么不同的地方:
上面代码翻译成自然语言如下:
(1)定义了一个普通函数A
(2)在A中定义了普通函数B
(3)在A中返回B(确切的讲,在A中返回B的引用)
(4)执行A(),把A的返回结果赋值给变量 c
(5)执行 c()
把这5步操作总结成一句扯淡的话就是:
函数A的内部函数B被函数A外的一个变量 c 引用
把这句扯淡的话再加工一下就变成了闭包的定义:
当一个内部函数被其外部函数之外的变量引用时,就形成了一个闭包。
2.demo是理解抽象东西的最好方法,下面来看一下闭包怎么用,又会在哪些地方能用到它呢。 |
(1.)改变字体的大小(点击不同的字体,改变body字体的大小)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script> window.onload = function() { function ftsize(sizes){ return function(){ document.body.style.fontSize=sizes+"px"; } } var fontsize12=ftsize(12); var fontsize14=ftsize(14); var fontsize16=ftsize(22); document.getElementById("font-size12").onclick=fontsize12; document.getElementById("font-size14").onclick=fontsize14; document.getElementById("font-size22").onclick=fontsize22; } </script> </head> <body> <a href="#" id="font-size12">12号字体</a> <a href="#" id="font-size14">14号字体</a> <a href="#" id="font-size22">22号字体</a> </body> </html>
(2.)用户小调查,当文本框获取焦点时提示用户输入正确的内容
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script> window.onload = function() { function showHelp(help) { document.getElementById('help').innerHTML = help; } function makeHelpCallback(help) { return function() { showHelp(help); }; } function setupHelp() { var helpText = [ {'id': 'email','help': '填写你正确的email地址'}, {'id': 'name', 'help': '填写你的真实姓名' }, {'id': 'age', 'help': '你的年龄必须大于16岁'} ]; for (var i = 0; i < helpText.length; i++) { var item = helpText[i]; document.getElementById(item.id).onfocus = makeHelpCallback(item.help); } } setupHelp(); } </script> </head> <body> <p id="help">用户小调查</p> <p>邮箱: <input type="text" id="email" name="email"></p> <p>姓名: <input type="text" id="name" name="name"></p> <p>年龄: <input type="text" id="age" name="age"></p> </body> </html>
(3.)点击不同的li时弹出对应的index
我们可以想到的一种方法就是用JQ循环每一个li获取下标代码如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script src="js/jquery.js"></script> <script> $(function() { $("li").each(function() { $(this).click(function() { alert($(this).index()); }) }) }) </script> </head> <body> <ul> <li>aaaaaa</li> <li>bbbbbb</li> <li>ccccccc</li> <li>dddddd</li> </ul> </body> </html>
我们不用JQ,用JS来实现呢代码如下:
<script> window.onload = function() { var nodes = document.getElementsByTagName("li"); for (i = 0; i < nodes.length; i += 1) { nodes[i].onclick = function() { alert(i); //值全是4 }; } } </script>
值全为4,这是为什么呢,当事件(li被点击)被执行时,外层函数的for循环早已结束,所以索引i已经变成4,因此我们点击后会返回里层函数变量对象指向的值i也就是4;解决这个问题我们这时又可以用到闭包了
代码如下:
function alertindex(nodes) { var helper = function(a) { return function() { alert(a); }; }; var i = 0; for (i = 0; i < nodes.length; i++) { nodes[i].onclick = h elper(i); } }; alertindex(document.getElementsByTagName("li")); }
i是alertindex中的一个变量,它的值在helper中被引用,当for循环一次函数helper就被调用执行一次,i的值就在原来的基础上累加1。因此,alertindex中的i一直保存在内存中。即得到我们想要的结果。
这就是闭包的作用,有时候我们需要一个模块中定义一个变量:希望这个变量一直保存在内存中但又不会“污染”全局的变量,这个时候,我们就可以用闭包来定义这个模块。
总结 |
有了简单的理解和应用之后,在以后的更多的实践应用中会对闭包有越来越多越深的理解。
参考:http://www.codeceo.com/article/javascript-closures.html(让你分分钟学会 JavaScript 闭包)
https://www.zhihu.com/question/31383111(怎么更好的理解闭包)
https://www.zhihu.com/question/28849447(到底该如何理解闭包)
https://www.zhihu.com/question/19554716(JavaScript 里的闭包是什么?应用场景有哪些?)