설명이 필요한 removeEventListener () 문제가 발생했습니다.
이벤트 리스너에 매개 변수를 전달할 수 있기를 원했기 때문에 이벤트 리스너를 생성하는 함수를 작성했습니다. 그러면 의도 한 이벤트 리스너를 콜백으로 호출하는 두 번째 함수가 반환됩니다.
전체 라이브러리 파일은 다음과 같습니다.
function EventHandlerConstants()
{
this.SUCCESS = 0;
this.NOTFUNCTION = 1;
}
function MakeEventHandler(actualHandler, selfObject, args)
{
var c = new EventHandlerConstants();
var funcReturn = null;
var res = {
"status" : c.SUCCESS,
"actualHandler" : null
};
if (IsGenuineObject(actualHandler, Function))
{
res.actualHandler = function(event) {
var trueArgs = [event].concat(args);
actualHandler.apply(selfObject, trueArgs);
};
}
else
{
res.status = c.NOTFUNCTION;
}
return(res);
}
그런 다음 이것이 의도 한대로 작동하는지 알아보기 위해 빠른 테스트 페이지를 작성하고 원하는대로 이벤트 처리기를 추가하고 제거 할 수 있도록했습니다.
HTML 테스트 페이지는 다음과 같습니다.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="NewEventTest.css">
<script language = "JavaScript" src="BasicSupport.js"></script>
<script language = "JavaScript" src="EventHandler6.js"></script>
</head>
<body class="StdC" id="MainApplication">
<button type="button" class="StdC NoSwipe" id="Button1">Try Me Out</button>
<button type="button" class="StdC NoSwipe" id="Button2">Alter The 1st Button</button>
</body>
<script language = "JavaScript" src="NewEventTest.js"></script>
</html>
완전성을 위해 다음과 같은 간단한 CSS 파일도 사용합니다.
.StdC {
color: rgba(255, 255, 255, 1);
background-color: rgba(0, 128, 0, 1);
font-family: "Book Antiqua", "Times New Roman", "Times", serif;
font-size: 100%;
font-weight: normal;
text-align: center;
}
.NoSwipe {
user-select: none;
}
테스트 코드는 다음과 같습니다.
function GlobalVariables()
{
this.TmpRef1 = null;
this.TmpRef2 = null;
this.TmpRef3 = null;
this.Const1 = null;
this.Handler1 = null;
this.Handler2 = null;
this.Handler3 = null;
this.EventOptions = {"passive" : true, "capture" : true };
}
function Button1Initial(event)
{
console.log("Button 1 initial event handler triggered");
}
function Button1Final(event)
{
console.log("Button 1 final event handler triggered");
}
function Button2Handler(event, oldFunc, newFunc)
{
var funcRef = null;
this.removeEventListener("click", oldFunc);
this.addEventListener("click", newFunc, GLOBALS.EventOptions);
}
GLOBALS = new GlobalVariables();
GLOBALS.Const1 = new EventHandlerConstants();
GLOBALS.TmpRef1 = document.getElementById("Button1");
GLOBALS.TmpRef2 = MakeEventHandler(Button1Initial, null, []);
if (GLOBALS.TmpRef2.status == GLOBALS.Const1.SUCCESS)
{
GLOBALS.Handler1 = GLOBALS.TmpRef2.actualHandler;
GLOBALS.TmpRef1.addEventListener("click", GLOBALS.Handler1, GLOBALS.EventOptions);
}
GLOBALS.TmpRef1 = MakeEventHandler(Button1Final, null, []);
if (GLOBALS.TmpRef1.status == GLOBALS.Const1.SUCCESS)
{
GLOBALS.Handler3 = GLOBALS.TmpRef1.actualHandler;
}
GLOBALS.TmpRef1 = document.getElementById("Button2");
GLOBALS.TmpRef2 = document.getElementById("Button1");
GLOBALS.TmpRef3 = Button1Final;
GLOBALS.TmpRef4 = MakeEventHandler(Button2Handler, GLOBALS.TmpRef2, [GLOBALS.Handler1, GLOBALS.Handler3]);
if (GLOBALS.TmpRef4.status == GLOBALS.Const1.SUCCESS)
{
GLOBALS.Handler2 = GLOBALS.TmpRef4.actualHandler;
GLOBALS.TmpRef1.addEventListener("click", GLOBALS.Handler2, GLOBALS.EventOptions);
}
따라서 수행 할 테스트는 다음과 같습니다.
[1] 클릭 이벤트 핸들러를 버튼 # 1에 연결합니다.
[2] 버튼을 클릭 할 때 이벤트 핸들러가 호출되는지 테스트합니다.
[3] 테스트가 통과되면 Button # 2를 클릭하고 그에 연결된 이벤트 핸들러를 호출합니다. 그러면 Button # 1에 연결된 이전 이벤트 핸들러가 제거되고 새 이벤트 핸들러로 대체됩니다.
단계 [1] 및 [2]는 정상적으로 작동합니다. 이벤트 핸들러가 첨부되고 버튼을 클릭 할 때마다 호출됩니다.
문제는 단계 [3]에 있습니다.
특히 단계 [3]에서 해당 이벤트 리스너를 제거하기 위해 MakeEventHandler ()에 의해 생성 된 함수에 대한 참조를 저장하더라도 removeEventListener ()를 호출해도 이벤트 리스너가 제거되지 않습니다. 이후에 Button # 1을 클릭하면 내가 제거한 것으로 추정되는 것을 포함하여 두 이벤트 리스너가 모두 실행됩니다!
말할 필요도없이이 동작은 모든 것을 신중하게 설정 했음에도 불구하고 내가 removeEventListener () 호출에서 지정한 함수가 처음에 addEventListener ()로 추가 한 자체 동일한 함수가되도록 설정 했음에도 불구하고 당황스러워 합니다. 주제에 대한 모든 문서에 따르면 '각 호출에 대해 동일한 기능에 대한 참조를 전달 (이 스레드 포함) 읽었 해야 작동하지만 명확하지 않습니다.
단계 [1]에서 예상대로 콘솔의 테스트 출력은 다음과 같습니다.
버튼 1 초기 이벤트 핸들러가 트리거 됨
코드는 예상대로 [2] 단계에서 실행되며 코드를 단계별로 추적하면 실제로 코드가 예상대로 실행됨을 알 수 있습니다.
그러나 단계 [3] 에서 버튼 # 1을 처음 클릭하면 원하는 결과를 얻을 수 있습니다.
버튼 1 최종 이벤트 핸들러가 트리거 됨
무슨 일이 버튼 # 1에 클릭 할 때 발생 이후 이 있습니다 :
버튼 1 초기 이벤트 핸들러가 트리거 됨 버튼 1 최종 이벤트 핸들러가 트리거 됨
확실히, 처음에 Button # 1에 연결된 함수가 클로저 내에서 생성 되었기 때문에 여전히 메모리에 유지 되더라도 요소에 대한 이벤트 리스너 컬렉션에서 분리되어야합니까? 왜 여전히 연결되어 있습니까?
또는 이벤트 리스너와 함께 클로저를 사용하는 것과 관련된 이상한 버그가 발생 했습니까?