[英]Javascript closure scope
我今天在一個前端Javascript項目中工作。 我將盡力使問題描述和解決方案盡可能簡短。 我必須在頁面上的鏈接上添加點擊處理程序,以將用戶重定向到其他頁面,所以我有2個Javascript數組arrayOfRedirectLinks
和pageLinkElements
:
var arrayOfRedirectLinks, pageLinkElements;
最初,我是這樣編寫addEventHandlers
函數的:
var addEventHandlers = function() {
var i, link;
for( var i in arrayOfRedirectLinks) {
link = arrayOfRedirectLinks[i];
pageLinkElements[i].addEventListener('click', function(e) {
e.preventDefault();
window.location = link;
});
}
}
我以為這個解決方案將一直arrayOfRedirectLinks
,直到...打開我的瀏覽器,單擊了幾個鏈接,然后注意到所有這些鏈接都將我重定向到了同一鏈接( arrayOfRedirectLinks
的最后一個鏈接)。
最終,我發現我的問題類似於此處發布的問題,它是在for循環中創建的Javascript多個動態addEventListener-傳遞參數無效
確實,在那里發布的第一個和第二個解決方案都對我有用
var addEventHandlers = function() {
var i, link;
for( var i in arrayOfRedirectLinks) {
(function(link){
link = arrayOfRedirectLinks[i];
pageLinkElements[i].addEventListener('click', function(e) {
e.preventDefault();
window.location = link;
});
}(link));
}
}
和
var passLink = function(link) {
return function(e) {
e.preventDefault();
window.location = link;
};
};
var addEventHandlers = function() {
var i, link;
for( var i in arrayOfRedirectLinks) {
link = arrayOfRedirectLinks[i];
pageLinkElements[i].addEventListener('click',passLink(link));
}
}
現在這似乎可行,但我不明白為什么可行。 我附帶以下說明,希望有人可以確認是否正確:
當我使用Javascript聲明函數時,它會在聲明該函數的函數范圍內獲取對變量的引用。 (即我的事件處理程序在addEventHandlers
函數中獲取對link
變量的引用)
因為處理程序獲得了對變量link
的引用。 當我將值重新分配給link
變量時,單擊處理程序被觸發時將使用的值也會更改。 因此,事件處理程序中的link
變量不是簡單地復制具有與添加函數處理程序時不同的內存地址和相同值的link
,而是它們都共享相同的內存地址,因此具有相同的值。
由於2)中所述的原因,所有單擊處理程序都將使用重定向到同一link
,即arrayOfRedirectLinks
數組中的最后一個link
,因為這是將在for
循環結束時分配給link
變量的最后一個值。
但是,當我將link
變量作為參數傳遞給另一個函數時,會創建一個新的作用域,並且該作用域內的link
實際上僅與傳遞給該函數的link
參數的值共享其初始值。 2個link
變量的引用不同。
由於4),當我將link
傳遞給click處理程序時,它將引用對Instantly Invoked Function Expression中的link
變量的引用,該變量本身與addEventHandlers
函數中的link
不共享相同的地址。 因此,來自事件處理程序功能的每個link
都將與其他link
隔離開,並將保留arrayOfRedirectLinks[i]
的值。
這個對嗎?
這是關鍵的一點:
var i, link;
for( var i in arrayOfRedirectLinks) {
link = arrayOfRedirectLinks[i];
pageLinkElements[i].addEventListener('click', function(e) {
e.preventDefault();
window.location = link;
});
}
這里只有一個link
變量。 請注意,僅在單擊鏈接時才調用addEventListener
回調函數。
到那時,變量link
具有最終值,所有事件處理程序功能都共享該值。
因此,所有鏈接都執行相同的操作。
最簡單的解決方案(除了更廣泛的重構之外):
for(var i in arrayOfRedirectLinks) {
(function(i) {
var link = arrayOfRedirectLinks[i];
pageLinkElements[i].addEventListener('click', function(e) {
e.preventDefault();
window.location = link;
});
}(i));
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.