其實函數引用的外部變量都是最後一次的值。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> #box{ width:100px; height:100px; background-color:pink; } </style> <script src="index.js"></script> </head> <body> <div id="box"></div> </body> </html> ///////////////////////////////js代碼////////////////////////// window.onload = function(){ var box = document.getElementById("box"); var num = 0; function a(){ console.log(num); } box.onclick = function(){ num ++; a(); // 1,2,3,4....每次單擊都會加1,說明函數引用外部變量是引用那個變量的最後一次的值。 } }
再來看一個例子:
window.onload = function(){ var box = document.getElementById("box"); var num = 0; for(var i=0;i<10;i++){ box.onclick = function(){ console.log(i); //總是打印10 } } }
如果你知道作用域鏈就好辦多了,在這個函數裡面的i其實引用的是最後一次i的值,為什麼不是1,2,3,4...呢?因為在你for循環的時候,你並沒有執行這個函數,你這個函數是在你點擊的時候才執行的,當執行這個函數的時候,它發現它自己沒有這個變量i,於是向它的作用域鏈中查找這個變量i,因為當你單擊這個box的時候已經for循環完了,所以儲存在作用域鏈裡面的i的值就是10,最後就打印出來10了。
for(var i=0;i<10;i++){ function a(){ console.log(i); } a(); //1,2,3,4,5.... }
為什麼這樣就可以呢?因為你在循環變量i的時候已經執行了函數a,自然變量i是什麼就打印出來什麼。
現在知道為什麼綁定事件的時候打印出來的是最後一次的for循環的值了吧。
如果你知道理解這段話,我相信你知道怎麼去解決這個問題。
解決方法1:讓這個函數直接執行。
解決方法2:將每次for循環中的變量i保存到某個地方。
方法1:
window.onload = function(){ var box = document.getElementById("box"); var num = 0; for(var i=0;i<10;i++){ box.onclick = a(); function a(){ console.log(i); //1,2,3,4..... } } }
雖然這樣可以打印出每次的變量i的值,但是我們沒有點擊box的時候它已經執行完了,直接無視了點擊事件,也就是說這個點擊事件已經可有可無了,所以我們用這種方法在綁定事件中就顯得不那麼可用了,那我們用方法2試試吧。
方法2:
window.onload = function(){ var div = document.getElementsByTagName("div"); var num = 0; for(var i=0;i<div.length;i++){ (function(i){ div[i].onclick = function(){ console.log(i); } })(i) } }
成功打印每個i的值,原理就是通過自執行函數,並且將變量i保存到這個自執行函數的參數中。如果你不知道什麼是自執行函數可以看初識js中的閉包這一節。
你們我們應該選擇那種方法呢?當然看你的情況了,如果沒有關於綁定事件的話,就是說讓這個函數直接執行的,那就用方法1,否則用方法2,另外方法2通用,但是因為裡面的i會一直保存到內存中比較消耗性能的原因,所以在沒有必要的情況下盡量不要用這種方式,其實還可以將i綁定到元素的屬性上。