2014-11-08 42 views
4

我發現這個在D3:什麼是JavaScript中的「防衛參考」?

function d3_dispatch_event(dispatch) { 
    var listeners = [], 
     listenerByName = new d3_Map; 

    function event() { 
    var z = listeners, // defensive reference 
     i = -1, 
     n = z.length, 
     l; 
    while (++i < n) if (l = z[i].on) l.apply(this, arguments); 
    return dispatch; 
    } 

    event.on = function(name, listener) { 
... 

Link to a line on github

什麼是 「防禦性的參考」 這裏的意思?

+0

它在JavaScript中沒有意義。它只對該評論的作者有意義。 – 2014-11-08 18:24:24

+0

@squint漂亮的漁獲(#58線)。讓我接受你的答案,如果你會創建它,並刪除此評論:)。 – Leviathan 2014-11-08 18:55:04

+1

我對此並不完全正確。看起來這條線是爲了去除。雖然它可以確保刪除項目仍然可以訪問(我想這就是他們想要的),[第63行](https://github.com/mbostock/d3/blob/master/src/event/dispatch.js# L63)確實在'listeners'中執行'.push()'。但是,由於他們爲'while'循環緩存'.length',所以添加的項目將不會被觸及。所以我想這只是爲了刪除,以便刪除的處理程序仍然會觸發。繼續並給出答案。我不確定我是否分析過所有角度,我需要重新開始工作! :-) – 2014-11-08 19:03:33

回答

2

實現事件系統時的問題是激發偵聽器的權利。調用回調時更改偵聽器列表可能會導致意外的行爲。

例如,假設有2個聽衆收聽事件x。事件x被觸發,系統開始將聽衆從index 0循環到index 1。聽衆index 0首先被解僱。回調被調用,並且回調發生在index 1刪除監聽器。循環將繼續進行,並嘗試在index 1處觸發回叫。監聽器不再存在,併發生異常。

這是真正簡化的例子,當在循環時更改偵聽器列表時可能會出錯。通過在循環之前計算偵聽器的數量,可輕鬆處理列表中的添加項。處理循環移除操作要複雜得多。

在d3中,每個從偵聽器列表中移除動作都將導致創建新的偵聽器數組,並將該數組作爲變量listeners的值。

listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1)); 

偵聽器的原始數組未被更改,因此循環將工作,但對原始數組的引用將丟失。這就是爲什麼event函數會創建對其的本地引用。通過defensive reference作者可能意味着創建listeners當前(循環前)值的臨時引用,即使listeners的值在循環的某個點發生更改也是如此。