2015-06-22 81 views
3

我經歷JavaScript權威指南 David Flanagan着的,我被困在下面的例子:一個循環內固定封閉

window.onload = function() { 
    var elements = document.getElementsByClassName("reveal"); 
    for(var i = 0; i < elements.length; i++) { 
     var elt = elements[i]; 
     var title = elt.getElementsByClassName("handle")[0]; 
     title.onclick = function() { 
      if(elt.className == "reveal") elt.className = "revealed"; 
      else if(elt.className == "revealed") elt.className = "reveal;" 
     } 
    } 
}; 

<div class="reveal"> 
    <h1 class="handle">Click Here to Reveal Hidden Text</h1> 
    <p>This paragraph is hidden. It appears when you click on the title.</p> 
</div> 

的問題是,在目前形式的代碼作品,但如果我要添加多個div與類reveal,無論我點擊什麼h1元素,只有最後一個會展開。我應該在代碼中更改哪些內容才能在獨立的div上工作?

P.S.我確實明白,由於問題的本質是循環中的閉包,所以這種問題經常被問到,但是我不能使我的代碼在SO上類似問題的解決方案中工作。謝謝。

+0

我會用事件代理並綁定到容器中,這樣一來,任何添加之後準備去。 – dandavis

+0

有點更好閱讀,但可以使用'var title = elt.querySelector(「。handle」);'而不是手動返回HTML集合的第一個實例。 –

+0

請向我們展示您嘗試使用閉包。這確實是解決方案。 – Bergi

回答

4

在JavaScript中,變量範圍設置爲功能級別。函數創建閉包,它們基本上定義了範圍的邊界。 A 子範圍可以訪問在父範圍中定義的變量,但不能以其他方式訪問。

當調用onclick處理函數,它必須尋找作用域鏈找到變量elt因爲elt不是當前範圍內聲明。

範圍鏈中的下一級是您的window.onload處理函數(即閉包)。在這個範圍內,變量elt聲明,它的值由循環設置。 但是請記住,當您單擊<h1>並調用onclick處理程序時,循環已終止。因此,elt將始終是循環中設置的最後一個值。這就是爲什麼你總是得到elt作爲最後一個元素。

要解決此問題,您可以使用立即執行函數。即時執行函數創建一個新的閉包(和範圍),其中elt在本地聲明。由於變量elt在這個新的內部範圍現在宣佈,它不會被父範圍內循環修改:

window.onload = function() { 
    var elements = document.getElementsByClassName("reveal"); 
    for(var i = 0; i < elements.length; i++) { 
     var elt = elements[i]; 
     var title = elt.getElementsByClassName("handle")[0]; 
     title.onclick = (function(elt) { 
      return function() { 
       if(elt.className == "reveal") elt.className = "revealed"; 
       else if(elt.className == "revealed") elt.className = "reveal;" 
      }; 
     })(elt); 
    } 
};