5,閉包
閉包意味著內層的函數可以引用存在於包圍它的函數內的變數,即使外層函數的執行已經終止。
讓我們先來看一個閉包的例子。
<script type="text/javascript"> function add(num){ return function(toAdd){ return num+toAdd; //代碼① } } var addFive = add(5); //此時addFive為function(toAdd){return num+toAdd;} var count = addFive(3); //此時count為 num+toAdd alert(count);//8 </script>
[Ctrl+A 全選 注:如需引入外部Js需重新整理才能執行]
代碼①是處於函數內層,不過它可以使用外層的變數num。
閉合還能解決另一個常見的Js問題,全域變數的影響。
通過自動執行匿名函數組合閉包,便可把原本屬於全域的變數隱藏起來。看下面的例子:
<script type="text/javascript"> (function(){ var msg = "Hello"; window.onunload = function(){ alert(msg);//輸出Hello } })() //alert(msg);//出現未定義 </script>
[Ctrl+A 全選 注:如需引入外部Js需重新整理才能執行]
在使用setTimeout時,我們經常也用上了閉包。
<html> <head> <title>demo</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript"> window.onload = function(){ var obj = document.getElementById("abc"); obj.style.border = "1px solid #000"; setTimeout(function(){ obj.style.color = "red"; },1000) function DeAlert(msg , time){ setTimeout( function(){ alert(msg); },time) } DeAlert("hello",2000); } </script> </head> <body> <div id="abc">CssRain</div> </body> </html>
[Ctrl+A 全選 注:如需引入外部Js需重新整理才能執行]
以這種方式使用setTimeout(),可以避免一些問題。
當然使用閉包 也會帶來一些問題。如下代碼所示:
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>demo</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript"> window.onload = function(){ var ul = document.getElementById("abc"); var li = document.getElementsByTagName("li"); for(var i=0;i<li.length;i++){ li[i].onclick = function(){ alert("你單擊的是第"+i+"個li。"); } } } </script> </head> <body> <ul id="abc"> <li>AAA</li> <li>BBB</li> <li>CCC</li> </ul> </body> </html>
[Ctrl+A 全選 注:如需引入外部Js需重新整理才能執行]
單擊li彈出的序號為 3 ,並不是正確的序號,它引用的值是最後一次的賦值。
我們可以使用下面代碼來解決:
<script type="text/javascript"> window.onload = function(){ var ul = document.getElementById("abc"); var li = document.getElementsByTagName("li"); for(var i=0;i<li.length;i++){ (function(){ //使用一個自執行的匿名函數 來激發出範圍 var b = i ; //記住在這個範圍內的值 li[b].onclick = function(){ //使用剛才記住的值,變數b alert("你單擊的是第"+b+"個li。"); } })() } } </script>
[Ctrl+A 全選 注:如需引入外部Js需重新整理才能執行]
通過使用閉包對範圍的控制,從而符合了我們的要求。
上面的代碼可以分解為:
<script type="text/javascript"> window.onload = function(){ var ul = document.getElementById("abc"); var li = document.getElementsByTagName("li"); function a(){ var b = 0 ; li[b].onclick = function(){ alert("你單擊的是第"+b+"個li。"); } } function b(){ var b = 1 ; li[b].onclick = function(){ alert("你單擊的是第"+b+"個li。"); } } function c(){ var b = 2 ; li[b].onclick = function(){ alert("你單擊的是第"+b+"個li。"); } } a(); b(); c(); } </script>
[Ctrl+A 全選 注:如需引入外部Js需重新整理才能執行]
閉包的概念不容易掌握,我也是花了大量時間和精力才理解。
6,小結
筆記(2),(3),(4)講解了 JavaScript中的幾個重要的內容,包括引用,函數重載,範圍,內容物件和閉包。
引用的關鍵內容: 指標,數組引用,字串引用,區別,傳值,傳址。
函數重載的關鍵內容: 參數的數量,參數的類型,arguments,偽數組,typeof,constructor,區別-字串和對象。
範圍的關鍵內容: 函數劃分,全域範圍,全域對象,window對象的屬性,局部範圍,顯式聲明,隱式聲明。
內容物件的關鍵內容: this變數,call,apply,參數區別,數組。
閉包的關鍵內容: 內層函數,外層函數,變數,setTimeout,閉包問題,最後一次的賦值,閉包和範圍。