[Javascript] addEventListener()와 removeEventListener()

박기영·2023년 3월 28일
0

Javascript

목록 보기
33/45

removeEvnetListener()를 사용할 때 정상적으로 작동하지 않는 경우가 있다.
이유를 잘 몰랐는데 이번에 addEventListener()와의 관계를 정리를 해보려고 한다.

addEventListener()

이벤트가 발생했을 때, 콜백 함수가 실행되게 해주는 함수이다.
보통 아래와 같은 방법으로 사용한다.

// 방법 1. 함수 선언 후 콜백 함수로 사용하기
function clickHandler () {
  console.log("hi");
}
 
tag.addEventListener("click", clickHandler);

// 방법 2. 익명 함수를 콜백 함수로 사용하기
tag.addEventListener("click", () => {
  console.log("hi");
})

이벤트 객체를 넘겨주지 않아도 된다.

필자는 addEventListener()에서 콜백 함수에 이벤트를 전달할 때 항상 아래와 같은 코드를 사용했다.

const input = document.getElementsByClassName("in")[0];

function inputHandler(e) {
  console.log(e.target.value);
}

input.addEventListener("change", (e) => inputHandler(e));

input 태그의 value를 가져오거나 할 때,
주로 e.target.value를 사용해서 받아오기 위해 사용하는데,
꼭 이렇게 사용할 필요가 없다.

const input = document.getElementsByClassName("in")[0];

function inputHandler(e) {
  console.log(e.target.value);
}

input.addEventListener("change", inputHandler);

이벤트 객체를 넘겨주는 것을 명시하지 않아도 동일하게 사용할 수 있다.
위의 두 코드의 결과는 아래와 같이 동일하게 나온다.

참고 동영상

이렇게 addEventListener()를 사용해서 이벤트를 등록해줬다면 끝일까?
활용도가 없는 addEventListener()는 삭제해줘야지 메모리 누수를 막을 수 있으므로
removeEvnetListener()를 해줘야한다.

removeEvnetListener()

위에서 살펴본 예시에 대하여 removeEvnetListener()를 작성해본다면 아래와 같을 것이다.

// 방법 1. 함수 선언 후 콜백 함수로 사용하기
tag.removeEvnetListener("click", clickHandler);

// 방법 2. 익명 함수를 콜백 함수로 사용하기
tag.removeEvnetListener("click", () => {
  console.log("hi");
})

음..! 잘했군!
그럴리가 없다.

addEventListener()에서는 두 방법이 전혀 문제없이 작동한다.
그러나, removeEvnetListener()에서는 방법 1만이 정상 작동한다.

즉, 익명 함수를 콜백 함수로 사용하는 경우에는 removeEvnetListener()가 작동하지 않는다.

정상 작동하는 경우

극단적인 예시를 한번 만들어봤다.

const btn = document.getElementsByClassName("btn")[0];

function clickHandler() {
  console.log("hi");
}

btn.addEventListener("click", clickHandler);
btn.removeEventListener("click", clickHandler);

이벤트 발생을 탐지함과 동시에 제거해버렸기 때문에, 버튼을 클릭해도 아무런 일이 발생하지 않는다.

참고 동영상

앞서 말했지만, 일반적인 함수를 콜백 함수로 사용하는 경우에는 전혀 문제가 없다.

정상 작동하지 않는 경우

이번에는 콜백 함수를 익명 함수로 사용해봤다.

const btn = document.getElementsByClassName("btn")[0];

btn.addEventListener("click", () => {
  console.log("hi");
});

btn.removeEventListener("click", () => {
  console.log("hi");
});

참고 동영상

일반 함수에서 익명 함수로 바꿨을 뿐인데, 이벤트 제거가 작동을 하지 않게 되었다.

왜 이렇게 되는 걸까?

ChatGPT 님께서는 아래와 같이 답변을 해주셨다.
물론, 구글링을 따로 해본 결과 전부 같은 답변을 얻을 수 있었다.

참고 이미지

익명 함수는 참조를 유지하지 않기 때문에 같은 함수인지 판단할 수 없다.

즉, 익명 함수에 대해서는 사용되었던 함수를 제거하는게 아니라, 전혀 다른 함수를 제거하고 있기 때문에
결과적으로 제거되지 않는 것으로 보이는 것이다.

구글링을 해보면 방법이 아예 없는 것은 아니지만, 정말 귀찮은

익명 함수는 제거할 수 없는가?

아니다. 제거할 수는 있다.

const btn = document.getElementsByClassName("btn")[0];

// 익명 함수
const clickHandler = function () {
  console.log("hi");
};

btn.addEventListener("click", clickHandler);

btn.removeEventListener("click", clickHandler);

위와 같은 코드처럼 익명 함수를 설정하면 제거할 수 있다.
그런데...이러면 그냥 일반 함수를 선언해서 사용하는게 훨씬 나을 것 같다.

{once : true} 사용하여 제거하기

아니면 removeEventListener()를 애초에 사용하지 않는 방법도 있다.
addEventListener()의 3번 째 인자로 옵션을 넘겨줄 수 있는데,
다음과 같이 사용하면 이벤트를 한번만 사용하고 제거할 수 있다.

const btn = document.getElementsByClassName("btn")[0];

btn.addEventListener(
  "click",
  () => {
    console.log("hi");
  },
  { once: true }
);

참고 이미지

잊지 말아야 할 것은 이벤트가 한번만 실행된다는 것이다.
여러 번 실행하거나, 지속적으로 실행해야하는 경우에는 직접 removeEventListener()를 써야한다.

참고 자료

semicolonandsons 게시글
stackoverflow 질문글
inpa님 블로그
hianna님 블로그

profile
나를 믿는 사람들을, 실망시키지 않도록

0개의 댓글