在JavaScript中怎樣利用閉包
來源:互聯網
上載者:User
JavaScript的變數範圍是通過函數來維護的。舉個例子,對於函數:function add(a,b){return a+b;}而言,當使用不同的參數(不帶參數的函數同樣如此)調用它時:var sum1 = add(1,2);var sum2 = add(3,4);每次調用都會通過建立一個新的調用對象維護一個新的函數範圍,從而保證了sum1和sum2分別取得相應的 值3和7。而閉包的原理,也是如此。下面舉兩個例子,一個是因為閉包導致了問題,而另一個則利用閉包巧妙地通過函數的範圍綁定參數。這兩個例子相關的HTML標記片斷如下:<a href=”#” id=”closureExample”>利用閉包的例子(0.5秒後您會看到提示)</a><a href=”#” id=”closureExample2″>由於閉包導致問題的例子1</a><a href=”#” id=”closureExample3″>由於閉包導致問題的例子2</a><a href=”#” id=”closureExample4″>由於閉包導致問題的例子3</a>例一:因遭遇閉包而導致問題上面標記片斷中有4個<a>元素,假設要給後三個指定事件處理常式,使它們在使用者單擊時報告自己在頁面中的順序,比如:當使用者單擊第2個連結時,報告“您單擊的是第2個連結”。為此,如果編寫下列為後三個連結添加事件處理常式的函數:function badExample() { for (var i=2 ; i<=4 ; i++ ) { var el = document.getElementById(’closureExample’ + i); el.onclick = function(){ alert(’您單擊的是第’ + i + ‘個連結’); } }}然後,在頁面載入完成後(不然可能會報錯)調用該函數:window.onload = function(){ badExample();}此時單擊後3個連結,會看到警告框中顯示什麼資訊呢?——全都是“您單擊的是第5個連結”。為什嗎?因為在badExample()函數中指定給el.onclick的事件處理常式——也就是那個匿名函數是在badExample()函數運行完成後(使用者單擊連結時)才被調用的。而調用時,需要對變數i求值,解析程式首先會在事件處理常式內部尋找,但沒有定義。然後,又到外部範圍,即badExample()函數中尋找,此時有定義,但i的值是5(只有i大於5才會停止執行for迴圈)。因此,就會取得該值——這正是閉包(匿名函數)要使用其外部函數(badExample)範圍中變數的結果。而且,這也是由於匿名函數本身無法傳遞參數(故而無法維護自己的範圍)造成的。這個例子的問題怎麼解決呢?大家自己想一想。例二:利用閉包綁定參數還是上面的HTML片段,我們要在使用者單擊第一個連結時延時彈出一個警告框——注意延時——怎麼實現?答案是使用setTimeout()函數,這個函數會在指定的毫秒數之後調用一個函數,如:setTimeout(someFunc,500);但問題是,無法給其中的someFunc函數傳遞參數。而使用閉包則可以輕鬆解決這個問題:function goodExample(i) {return function(){alert(i);};}函數goodExample用來返回一個匿名函數(閉包)。而我們可以通過為它傳遞參數來使返回的匿名函數綁定該參數,如:var good = goodExample(’這個參數是通過閉包綁定的’);而此時,就可以將綁定了參數的good函數傳遞給setTimeout()實現延時警告了:setTimeout(good,500) //此時good中已經綁定了參數最後,與為第一個連結指定事件處理常式結合起來,完整的代碼就是:window.onload = function(){var el = document.getElementById(’closureExample’);if (el){ var good = goodExample(’這個參數是由閉包綁定的’); el.onclick = function(){ setTimeout(good,500); }}}