2014-11-08 2 views
4

나는 D3이 발견 :자바 스크립트에서 "방어 참조"란 무엇입니까?

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에서는 의미가 없습니다. 그것은 그 주석의 저자에게 의미가 있습니다. –

+0

@ 스쿼트 멋진 잡기 (# 58 줄). 만약 당신이 그것을 만들고,이 코멘트를 제거 :) 대답을 수락하자. – Leviathan

+1

나는 완전히 그것에 대해 정확하지 않습니다. 그 선은 제거를위한 것 같습니다. 제거 항목을 계속해서 액세스 할 수 있지만 (원하는 항목이라고 생각됩니다), [행 63] (https://github.com/mbostock/d3/blob/master/src/event/dispatch.js# L63)은 실제로'listen '에'.push()'를 수행한다. 그러나, 그들은'while' 루프를 위해'.length'를 캐쉬했기 때문에, 추가 된 항목에는 도달하지 않습니다. 그래서 제거 된 핸들러가 여전히 발사되도록 제거하는 것입니다. 가서 대답 해주세요. 나는 모든 각도를 분석했는지 확신 할 수 없어 다시 일해야합니다! :-) –

답변

2

이벤트 시스템을 구현할 때의 문제점은 리스너를 올바르게 발동시키는 것입니다. 콜백을 호출하는 동안 리스너 목록을 변경하면 예기치 않은 동작이 발생할 수 있습니다.

예를 들어 이벤트을 수신하는 2 명의 청취자가 있다고 가정 해 봅시다. 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 함수가 함수에 대한 로컬 참조를 만듭니다. 저자는 아마도 listeners의 값이 루프의 어느 시점에서 변경 되더라도 보유하고있는 현재 (before 루프) 값 listeners에 대한 임시 참조를 만드는 것을 의미합니다.

관련 문제