先拋出原問題:javascript
for (var i = 0; i < 10; i++) { divs[i].onmouseover = function () { this.style.backgroundColor = "red"; this.style.left = -55*i; }; }
測試結果顯示:鼠標通過全部div時,北京顏色會變成紅色,可是全部div的定位都爲-55*10!這就是問題所在!html
正好在JS閉包理解上還不是很通透,爲找出問題所在,特地寫了一個小小的demo:java
<!DOCTYPE html> <html> <body> <div id="header"> <p id="p">This is a word!</p> </div> </body> <script type="text/javascript"> p.onclick = function() { var header = document.getElementById('header'); var p = document.getElementById('p'); // 生成十個測試的span for (var i = 0; i < 10; i++) { var ele_span = document.createElement("span"); ele_span.id = "id_" + i; ele_span.innerHTML = "This is" + i + "span"; header.appendChild(ele_span); }; var spans= document.getElementsByTagName("span"); for (var i = 0; i < 10; i++) { spans[i].onmouseover = function () { console.log(i); console.log(this); this.style.backgroundColor = "red"; } document.getElementById("id_"+i).onclick = function(i) { console.log(this); console.log(i); this.style.backgroundColor = "green"; } }; } </script> </html>
點擊段落,生成十個span,id從1~10,接着經過for循環爲每一個span綁定mouseover以及click事件,鼠標通過每一個元素時,背景顏色變成紅色,可是console.log(i)輸出永遠都是10。結果如圖:閉包
那試着把i經過參數傳遞到click綁定函數呢?狀況會怎樣?若是你認爲console.log(i)會輸出相應的i值,那你就被參數i騙了!參數i只是一個參數名,想寫成啥寫啥,不過通常的寫法都是e,覺得綁定事件,傳遞到時間函數的參數是事件自己,有圖有真相:app
這樣的話,想經過這樣把參數i值傳遞到時間函數裏是沒門了。這時候,閉包的功力就立體現了:函數
for (var i = 0; i < 10; i++) { document.getElementById("id_"+i).onclick = (function (i) { console.log(i); })(i); };
測試結果以下:測試
從結果能夠看出,匿名函數自動執行,並且每次循環的i值傳遞到匿名函數裏,這樣就實現值傳遞了。this
畫個小圖理解思路:spa
JavaScript也採用此法做用域,函數執行依賴於變量做用域,這個做用域是在函數定義時決定的,而不是調用時決定的。局部變量做用域具備局部性的,當JavaScript須要查找變量i時,先查找本做用域,這裏就是先查找事件函數,若是沒有查找到,就往上查找外部對象,這裏就查找到for循環裏的變量,此時找到了,就取得i的值,但此時i的值已經自增到10,因此console.log(i)輸出10;JavaScript變量查找經過變量的做用域查找,不斷往頂層做用域查找,直到global對象,若是在global對象中尚未查找到變量,就會拋出引用錯誤(ReferenceError)異常。code
這就是JavaScript變量做用域的特性的,能夠經過閉包實現變量保存在函數做用域中。