이벤트 처리기
1. 개요
1. 개요
이벤트 처리기는 웹 페이지나 애플리케이션에서 발생하는 특정 이벤트에 반응하여 실행되는 함수 또는 메서드이다. 이벤트 리스너 또는 이벤트 핸들러라고도 불린다. 이벤트 처리기의 주요 역할은 사용자의 상호작용, 예를 들어 마우스 클릭이나 키보드 입력에 반응하거나, 페이지 로드나 네트워크 요청 완료와 같은 시스템 이벤트를 처리하는 것이다.
이벤트 처리기는 프론트엔드 웹 개발과 GUI 프로그래밍의 핵심 개념으로, 비동기 프로그래밍 패러다임을 구현하는 데 필수적이다. 이를 통해 정적인 문서가 아닌 동적이고 반응적인 사용자 인터페이스를 만들 수 있다. 주로 HTML, 자바스크립트, DOM 환경에서 사용된다.
이벤트 처리기를 특정 HTML 요소에 연결하는 방법은 크게 세 가지가 있다. 첫째는 HTML 태그 내에 onclick과 같은 인라인 속성으로 직접 지정하는 방법이다. 둘째는 자바스크립트 코드에서 DOM 요소의 onclick 같은 프로퍼티에 함수를 할당하는 방법이다. 셋째로, 가장 유연하고 권장되는 방법은 addEventListener 메서드를 사용하여 이벤트 리스너를 등록하는 것이다.
2. 기본 개념
2. 기본 개념
2.1. 이벤트와 이벤트 처리기의 관계
2.1. 이벤트와 이벤트 처리기의 관계
이벤트 처리기는 웹 브라우저 환경이나 GUI 기반 애플리케이션에서 발생하는 특정 사건, 즉 이벤트에 반응하여 실행되는 함수 또는 메서드이다. 이벤트 리스너 또는 이벤트 핸들러라고도 불린다. 이벤트 처리기의 핵심 역할은 프로그램의 흐름을 사용자의 행동이나 시스템의 상태 변화와 연결하는 것이다. 이를 통해 정적인 문서가 아닌, 사용자와 상호작용하는 동적인 애플리케이션을 구현할 수 있다.
이벤트와 이벤트 처리기의 관계는 방아쇠와 그에 따른 동작의 관계에 비유할 수 있다. 이벤트는 특정 조건이 충족될 때 시스템에 의해 생성되는 신호이다. 대표적인 예로는 사용자가 마우스를 클릭하거나 키보드를 누르는 행위, 웹 페이지 로딩이 완료되는 시점, 또는 네트워크 요청에 대한 응답이 도착하는 것 등이 있다. 이벤트 처리기는 이러한 신호를 '듣고' 있다가, 신호가 발생하면 미리 정의된 코드 블록을 실행하여 적절한 응답을 한다.
이 관계를 설정하는 과정을 이벤트 바인딩 또는 등록이라고 한다. 특정 HTML 요소나 객체에 "이 이벤트가 발생하면 이 함수를 실행하라"고 지시하는 것이다. 예를 들어, 버튼 요소에 클릭 이벤트 처리기를 등록하면, 사용자가 그 버튼을 클릭할 때마다 등록된 함수가 호출되어 원하는 작업(예: 폼 제출, 메뉴 표시)을 수행하게 된다. 이는 비동기 프로그래밍의 기본 패턴 중 하나로, 이벤트 드리븐 프로그래밍의 근간을 이룬다.
따라서 이벤트 처리기는 프론트엔드 웹 개발의 상호작용성을 구현하는 필수적인 구성 요소이다. 시스템이나 사용자로부터의 비동기적 신호를 감지하고, 이를 처리하는 로직을 실행함으로써 애플리케이션의 흐름을 제어한다.
2.2. 등록(바인딩) 방법
2.2. 등록(바인딩) 방법
이벤트 처리기를 특정 HTML 요소나 DOM 객체에 연결하는 방법은 크게 세 가지가 있다. 가장 직접적인 방법은 HTML 태그 내부에 인라인 속성으로 작성하는 것이다. 예를 들어 <button onclick="handleClick()">과 같이 on 접두사가 붙은 속성에 실행할 자바스크립트 코드를 문자열로 지정한다. 이 방식은 구조(HTML)와 동작(JavaScript)이 혼재되어 유지보수가 어려울 수 있다.
두 번째 방법은 자바스크립트 코드 내에서 DOM 객체의 프로퍼티에 함수를 직접 할당하는 것이다. 예를 들어 document.getElementById('myButton').onclick = function() { ... }; 과 같이 사용한다. 이 방식은 인라인 방식보다는 관심사를 분리할 수 있지만, 하나의 이벤트 유형에 대해 하나의 처리기만 등록할 수 있다는 제한이 있다.
가장 권장되는 표준 방법은 addEventListener 메서드를 사용하는 것이다. 대상 객체에 대해 addEventListener('click', myFunction) 형태로 호출하여 처리기를 등록한다. 이 메서드의 주요 장점은 하나의 이벤트에 대해 여러 개의 처리기를 등록할 수 있으며, 이벤트 전파 단계(캡처링 또는 버블링)를 세밀하게 제어할 수 있다는 점이다. 또한 removeEventListener 메서드를 통해 등록된 처리기를 명시적으로 제거할 수 있어 메모리 관리에 유리하다.
2.3. 이벤트 전파 (버블링과 캡처링)
2.3. 이벤트 전파 (버블링과 캡처링)
이벤트가 DOM 트리에서 전파되는 방식을 설명하는 개념이다. 이벤트 전파는 크게 캡처링 단계와 버블링 단계로 나뉜다. 캡처링 단계에서는 이벤트가 최상위 조상 요소에서 시작하여 타깃 요소까지 하향식으로 전파된다. 반면, 버블링 단계는 이벤트가 타깃 요소에서 발생한 후, 상위 요소로 거슬러 올라가며 전파되는 과정이다. 대부분의 이벤트는 기본적으로 버블링 단계에서 처리된다.
addEventListener 메서드를 사용할 때 세 번째 매개변수로 useCapture 옵션을 지정하여 이벤트 리스너가 어느 단계에서 동작할지 제어할 수 있다. 이 값을 true로 설정하면 캡처링 단계에서 이벤트를 잡아내고, false 또는 생략하면 버블링 단계에서 이벤트를 처리한다. 이벤트 객체의 stopPropagation 메서드를 호출하면 현재 단계 이후의 전파를 중단시킬 수 있다.
이벤트 전파 메커니즘은 이벤트 위임 패턴의 기반이 된다. 여러 하위 요소에 공통된 이벤트 처리가 필요할 때, 각각에 개별적으로 이벤트 처리기를 등록하는 대신 하나의 공통 상위 요소에만 리스너를 등록하면 효율적으로 관리할 수 있다. 이는 버블링 단계에서 상위 요소가 하위 요소에서 발생한 이벤트를 감지할 수 있기 때문에 가능한 기법이다.
3. 구현 방식
3. 구현 방식
3.1. 인라인 이벤트 처리기
3.1. 인라인 이벤트 처리기
인라인 이벤트 처리기는 HTML 요소의 속성으로 직접 자바스크립트 코드를 작성하여 이벤트를 처리하는 가장 초기의 방식이다. 주로 onclick, onmouseover, onkeydown과 같은 속성명을 사용하며, 속성값으로 실행할 자바스크립트 코드 문자열을 할당한다. 이 방식은 간단한 프로토타입이나 소규모 스크립트에서 빠르게 적용할 수 있다는 장점이 있지만, HTML 구조와 로직이 강하게 결합되어 유지보수가 어렵고, 하나의 이벤트에 하나의 처리기만 등록할 수 있다는 제약이 있다.
구현은 매우 직관적이다. 예를 들어, 버튼을 클릭했을 때 경고창을 표시하려면 <button onclick="alert('클릭됨')">버튼</button>과 같이 작성한다. 더 복잡한 함수를 호출해야 할 경우, 속성값으로 해당 함수의 이름을 호출하는 코드를 문자열로 적는다. 이때 호출되는 함수는 반드시 전역 범위에 정의되어 있어야 하며, 이는 네임스페이스 오염을 초래할 수 있다.
이 방식은 현대적인 프론트엔드 웹 개발에서 권장되지 않는다. HTML과 자바스크립트의 관심사를 분리하지 못해 코드의 가독성과 재사용성을 떨어뜨리기 때문이다. 또한, 인라인으로 작성된 자바스크립트 코드 문자열은 런타임에 평가되므로 성능상의 미세한 손실이 발생할 수 있으며, 보안 측면에서 크로스 사이트 스크립팅 취약점을 유발할 위험이 있다. 따라서 대부분의 경우 addEventListener 메서드를 사용한 등록 방식으로 대체된다.
3.2. 프로퍼티 리스너
3.2. 프로퍼티 리스너
프로퍼티 리스너 방식은 HTML 요소의 DOM 객체에 접근하여, 해당 객체의 on 접두사가 붙은 프로퍼티에 함수를 직접 할당하는 방식으로 이벤트 처리기를 등록한다. 예를 들어, myButton.onclick = function() { ... } 과 같은 형태로 사용한다. 이 방식은 인라인 이벤트 처리기보다 자바스크립트 코드와 HTML 구조를 분리할 수 있어 유지보수성이 향상되며, DOM이 완전히 로드된 후에 실행되어야 정상적으로 동작한다는 특징이 있다.
그러나 프로퍼티 리스너 방식에는 중요한 제약이 존재한다. 하나의 이벤트 유형(예: click)에 대해 단 하나의 처리기 함수만 바인딩할 수 있다. 동일한 요소의 동일한 이벤트에 새로운 함수를 프로퍼티에 할당하면, 이전에 할당된 함수는 덮어쓰여지게 된다. 또한, 이 방식은 이벤트 전파 단계 중 버블링 단계에서만 동작하며, 캡처링 단계를 제어할 수 없다. 이벤트 리스너의 제거는 해당 프로퍼티에 null 값을 할당하는 것으로 간단히 수행할 수 있다.
이 방식은 addEventListener 메서드에 비해 기능이 제한적이지만, 코드가 직관적이고 간결하여 빠른 프로토타이핑이나 단일 핸들러만 필요한 간단한 경우에 여전히 사용된다. 그러나 하나의 요소에 동일한 이벤트에 대해 여러 개의 리스너를 등록해야 하거나, 이벤트의 캡처링 단계를 활용해야 하는 등의 복잡한 상호작용이 필요한 경우에는 addEventListener 메서드를 사용하는 것이 표준적인 방법이다.
3.3. addEventListener 메서드
3.3. addEventListener 메서드
addEventListener 메서드는 DOM 요소에 이벤트 처리기를 등록하는 표준적인 방법이다. HTML 인라인 속성이나 DOM 프로퍼티 할당 방식과 달리, 하나의 이벤트 유형에 대해 여러 개의 리스너 함수를 중복해서 등록할 수 있다는 점이 가장 큰 특징이다. 또한 이 메서드를 사용하면 이벤트의 전파 단계(캡처링 단계 또는 버블링 단계)를 명시적으로 지정할 수 있어, 이벤트 전파를 세밀하게 제어할 수 있다.
이 메서드의 기본 구문은 대상요소.addEventListener(이벤트유형, 실행할함수, 옵션) 형태이다. 여기서 '옵션'은 불리언 값이나 객체를 사용할 수 있으며, 객체를 사용할 경우 capture, once, passive 등의 세부 설정이 가능하다. 예를 들어, once: true로 설정하면 리스너가 한 번만 실행되고 자동으로 제거된다.
addEventListener로 등록한 이벤트 처리기는 removeEventListener 메서드를 사용해 명시적으로 제거할 수 있다. 이때 제거하려는 리스너 함수는 등록할 때 사용한 함수와 동일한 참조를 가져야 하므로, 익명 함수 대신 기명 함수를 사용하는 것이 일반적인 모범 사례이다. 이는 특히 SPA와 같이 동적으로 요소가 생성되고 제거되는 환경에서 메모리 누수를 방지하는 데 중요하다.
이 방식은 인터넷 익스플로러 9 이상을 포함한 모든 최신 웹 브라우저에서 광범위하게 지원되며, 자바스크립트를 이용한 현대적인 프론트엔드 개발의 핵심 도구로 자리 잡았다.
4. 주요 이벤트 유형
4. 주요 이벤트 유형
4.1. 마우스 이벤트
4.1. 마우스 이벤트
마우스 이벤트는 사용자가 마우스를 조작할 때 발생하는 사용자 인터페이스 이벤트이다. 주로 웹 페이지의 특정 요소와 사용자의 상호작용을 감지하고 처리하는 데 사용된다. 가장 기본적인 마우스 이벤트로는 요소를 클릭할 때 발생하는 click 이벤트가 있으며, 더블클릭을 의미하는 dblclick, 마우스 버튼을 누르는 순간과 떼는 순간을 각각 감지하는 mousedown과 mouseup 이벤트도 있다.
마우스 포인터의 이동과 관련된 이벤트도 중요하다. mousemove 이벤트는 포인터가 요소 위를 움직일 때 연속적으로 발생하며, mouseenter와 mouseleave는 포인터가 요소의 영역에 들어오고 나갈 때 한 번씩 발생한다. 비슷하게 mouseover와 mouseout 이벤트도 존재하지만, 이들은 자식 요소로의 진입과 이탈 시에도 발생하는 점에서 차이가 있다. 이러한 이벤트들은 툴팁 표시나 호버 효과 구현에 활용된다.
마우스 이벤트 객체는 이벤트가 발생한 정확한 위치 정보를 제공한다. clientX와 clientY 좌표는 현재 뷰포트(브라우저 창) 기준의 위치를, pageX와 pageY는 전체 문서 기준의 위치를 나타낸다. 또한 button 프로퍼티를 통해 어떤 마우스 버튼이 눌렸는지(왼쪽, 가운데, 오른쪽)를 판별할 수 있어 상황에 맞는 컨텍스트 메뉴를 제어하는 데 사용된다.
주요 이벤트 | 설명 |
|---|---|
| 요소를 클릭했을 때 (mousedown 후 mouseup이 같은 요소에서 발생). |
| 요소를 빠르게 두 번 클릭했을 때. |
| 요소 위에서 마우스 버튼을 눌렀을 때. |
| 눌려 있던 마우스 버튼을 뗐을 때. |
| 요소 위에서 마우스 포인터가 움직일 때. |
| 포인터가 요소의 영역 안으로 들어왔을 때 (버블링되지 않음). |
| 포인터가 요소의 영역 밖으로 나갔을 때 (버블링되지 않음). |
4.2. 키보드 이벤트
4.2. 키보드 이벤트
키보드 이벤트는 사용자가 키보드를 조작할 때 발생하는 사용자 인터페이스 상호작용을 처리한다. 주로 입력 폼의 제어나 키보드 단축키 구현, 게임의 컨트롤 등에 활용된다. 가장 기본적인 키보드 이벤트로는 키가 눌렸을 때 발생하는 keydown, 키를 눌렀다 뗐을 때 발생하는 keyup, 그리고 실제 문자가 입력되었을 때 발생하는 keypress 이벤트가 있다. 현대 웹 표준에서는 keypress 이벤트의 사용이 권장되지 않으며, keydown과 keyup을 주로 사용한다.
이벤트가 발생하면 생성되는 이벤트 객체는 어떤 키가 눌렸는지에 대한 정보를 담고 있다. keydown과 keyup 이벤트 객체의 key 프로퍼티는 눌린 키의 물리적인 값을 나타내는 반면, keypress 이벤트 객체의 keyCode나 charCode 프로퍼티는 입력된 문자의 유니코드 값을 제공했다. 현재는 key 프로퍼티를 사용하여 'Enter', 'Escape', 'a', '1'과 같은 키 값을 문자열로 확인하는 것이 표준 방식이다. 또한 ctrlKey, shiftKey, altKey, metaKey와 같은 프로퍼티를 통해 수식 키의 누름 상태를 함께 확인할 수 있어 복합적인 단축키를 구현하는 데 필수적이다.
키보드 이벤트 처리 시 주의할 점은 이벤트의 대상이다. 일반적으로 키보드 이벤트는 현재 포커스를 가지고 있는 요소를 대상으로 발생한다. 이를테면, 텍스트 상자나 텍스트 영역에 포커스가 있는 상태에서 키를 누르면 해당 요소에서 이벤트가 발생한다. 문서 전체에 키보드 이벤트를 적용하려면 document 객체에 이벤트 처리기를 등록하거나, 특정 요소가 포커스를 받지 못한 경우를 대비해 이벤트 위임 패턴을 사용할 수 있다.
키보드 이벤트를 사용할 때는 접근성을 고려해야 한다. 모든 기능이 마우스 없이 키보드만으로도 조작 가능해야 하며, 특히 Tab 키를 이용한 포커스 이동과 Enter 키를 이용한 활성화는 기본적으로 지원되어야 한다. 또한, 브라우저나 운영체제에 이미 할당된 기본 단축키와의 충돌을 피하고, 사용자 정의 단축키를 제공할 때는 그 정보를 사용자에게 명확히 알려주어야 한다.
4.3. 폼 이벤트
4.3. 폼 이벤트
폼 이벤트는 HTML 폼 요소와 사용자 상호작용에 관련된 이벤트를 말한다. 주로 입력 필드의 값 변경, 폼 제출, 초기화 등의 작업을 감지하고 처리하는 데 사용된다. 이러한 이벤트는 사용자 데이터를 수집하고 검증하는 과정에서 핵심적인 역할을 한다.
주요 폼 이벤트로는 submit, reset, change, input, focus, blur 등이 있다. submit 이벤트는 폼이 제출될 때, reset 이벤트는 폼이 초기화될 때 발생한다. change 이벤트는 <input>, <select>, <textarea> 등의 요소 값이 변경되고 포커스를 잃었을 때 발생하는 반면, input 이벤트는 값이 변경되는 즉시 발생한다는 차이가 있다. focus와 blur 이벤트는 요소가 포커스를 얻거나 잃을 때 발생한다.
폼 이벤트 처리기의 일반적인 사용 예는 데이터 유효성 검사다. 예를 들어, submit 이벤트에 처리기를 등록하여 폼 데이터를 서버로 전송하기 전에 필수 입력값을 확인하거나 이메일 형식을 검증할 수 있다. input 이벤트를 활용하면 사용자가 타이핑하는 동안 실시간으로 피드백을 제공하는 기능을 구현할 수 있다.
이벤트 처리기를 등록할 때는 addEventListener 메서드를 사용하는 것이 일반적으로 권장된다. 이를 통해 동일한 이벤트 유형에 대해 여러 개의 리스너를 등록할 수 있으며, 이벤트의 캡처링 단계를 제어할 수 있다. 특히 폼 제출 시 페이지가 새로고침되는 기본 동작을 막기 위해 이벤트 객체의 preventDefault 메서드를 호출하는 로직은 submit 이벤트 처리기 내에서 흔히 사용된다.
4.4. 문서/창 이벤트
4.4. 문서/창 이벤트
문서와 브라우저 창 자체의 상태 변화를 감지하고 처리하기 위한 이벤트 유형이다. 이벤트 처리기는 페이지의 생명주기나 창의 크기 변화와 같은 시스템적 이벤트에 반응하여 특정 로직을 실행하는 데 사용된다.
주요 이벤트로는 load와 DOMContentLoaded가 있다. load 이벤트는 페이지의 모든 리소스(이미지, 스타일시트 등)가 완전히 로드되었을 때 발생하며, DOMContentLoaded 이벤트는 HTML 문서 자체의 파싱과 DOM 트리 구성이 완료되는 즉시 발생한다. 따라서 초기화 스크립트 실행 시점을 결정하는 데 중요한 역할을 한다. 또한 beforeunload와 unload 이벤트는 사용자가 페이지를 떠나기 직전과 떠날 때 발생하여 데이터 저장 확인이나 정리 작업을 수행할 수 있게 한다.
창 관련 이벤트에는 resize와 scroll이 대표적이다. resize 이벤트는 브라우저 창의 크기가 변경될 때마다 발생하며, 반응형 웹 디자인을 구현할 때 레이아웃을 동적으로 조정하는 데 활용된다. scroll 이벤트는 사용자가 페이지를 스크롤할 때 발생하여 무한 스크롤 기능이나 특정 위치에 도달했을 때의 애니메이션 등을 구현하는 데 사용된다. 이러한 이벤트는 매우 빈번하게 발생할 수 있어, 성능을 위해 디바운싱이나 쓰로틀링 기법과 함께 사용하는 것이 모범 사례이다.
5. 이벤트 객체
5. 이벤트 객체
5.1. 공통 속성과 메서드
5.1. 공통 속성과 메서드
이벤트 객체는 이벤트 처리기에 자동으로 전달되는 객체로, 발생한 이벤트에 대한 상세 정보를 담고 있다. 모든 이벤트 객체는 기본적으로 Event 인터페이스를 상속하며, 특정 이벤트 유형에 따라 추가적인 속성과 메서드를 제공한다.
가장 널리 사용되는 공통 속성으로는 이벤트가 발생한 요소를 가리키는 target과 이벤트를 처리 중인 현재 요소를 나타내는 currentTarget이 있다. 이벤트의 유형을 문자열로 반환하는 type 속성과, 이벤트 전파 단계(캡처링, 타깃, 버블링)를 나타내는 eventPhase 속성도 기본적으로 제공된다. 또한, 이벤트가 발생한 시점의 마우스 좌표(clientX, clientY)나 눌린 키보드 키의 코드(keyCode 또는 key)와 같은 상황별 정보도 포함될 수 있다.
주요 공통 메서드에는 preventDefault()와 stopPropagation()이 있다. preventDefault() 메서드는 해당 이벤트의 고유한 기본 동작을 취소한다. 예를 들어, 앵커 요소의 클릭 시 페이지 이동을 막거나, 폼 제출 이벤트 시 페이지 새로고침을 방지하는 데 사용된다. stopPropagation() 메서드는 이벤트 전파를 현재 요소에서 중단시켜, 상위 또는 하위 요소로의 이벤트 버블링이나 캡처링을 막는다. 두 동작을 모두 수행하는 stopImmediatePropagation() 메서드도 있다.
이러한 속성과 메서드를 효과적으로 활용하면, 개발자는 이벤트의 출처를 정확히 판단하고, 원치 않는 브라우저 기본 동작을 제어하며, 복잡한 DOM 구조에서의 이벤트 흐름을 관리할 수 있다. 이는 사용자 인터페이스의 상호작용을 정교하게 구현하는 데 필수적이다.
5.2. 이벤트 기본 동작 방지
5.2. 이벤트 기본 동작 방지
이벤트가 발생하면 브라우저는 해당 이벤트에 연결된 이벤트 처리기를 실행할 뿐만 아니라, 해당 이벤트에 대한 기본 동작도 함께 수행한다. 예를 들어, <a> 요소를 클릭하면 지정된 URL로 이동하고, <form> 요소의 제출 버튼을 클릭하면 폼 데이터가 서버로 전송되며, 컨텍스트 메뉴(마우스 오른쪽 버튼 클릭)를 열면 브라우저의 기본 메뉴가 나타난다. 이러한 기본 동작을 취소하거나 방지해야 하는 경우가 많다.
이벤트의 기본 동작을 방지하기 위해서는 이벤트 객체의 preventDefault() 메서드를 사용한다. 이 메서드는 이벤트가 취소 가능한 경우에만 효과가 있으며, 호출하면 해당 이벤트의 기본 동작이 실행되지 않는다. 주로 submit, click, contextmenu, keydown 같은 이벤트에서 활용된다. 예를 들어, 폼 유효성 검사에 실패했을 때 submit 이벤트에서 preventDefault()를 호출하면 데이터 전송을 막을 수 있다.
preventDefault() 메서드는 이벤트의 전파, 즉 버블링과 캡처링에는 영향을 주지 않는다. 이벤트 전파를 중단하려면 stopPropagation() 메서드를 사용해야 한다. 두 메서드를 혼동하지 않도록 주의해야 한다. 한편, 이벤트 처리기 내부에서 false를 반환하는 것(인라인 방식이나 프로퍼티 리스너에서)도 일부 오래된 브라우저에서 기본 동작 방지와 비슷한 효과를 낼 수 있지만, 표준적이고 명시적인 방법은 preventDefault() 메서드를 사용하는 것이다.
5.3. 이벤트 전파 제어
5.3. 이벤트 전파 제어
이벤트 전파 제어는 이벤트 버블링과 이벤트 캡처링의 흐름을 프로그래밍적으로 조작하는 것을 의미한다. 이벤트 객체는 이 전파 과정을 제어할 수 있는 메서드를 제공한다.
가장 일반적으로 사용되는 메서드는 stopPropagation()이다. 이 메서드를 호출하면 현재 이벤트 처리기가 실행된 후, 이벤트가 더 이상 상위 또는 하위 요소로 전파되는 것을 막는다. 즉, 버블링 단계에서 상위 요소의 리스너가 실행되지 않도록 하거나, 캡처링 단계에서 하위 요소로의 전파를 중단할 수 있다. 더 강력한 제어를 위한 stopImmediatePropagation() 메서드도 있는데, 이는 동일한 요소에 등록된 다른 모든 이벤트 리스너의 실행까지 차단한다.
이벤트 전파를 완전히 중단하는 것 외에도, preventDefault() 메서드를 사용하여 이벤트의 기본 동작을 취소할 수 있다. 이는 전파 제어와는 별개의 개념이지만, 실제 사용 시 함께 고려되는 경우가 많다. 예를 들어, 앵커 요소의 클릭 이벤트에서 preventDefault()를 호출하면 페이지 이동을 막고, stopPropagation()을 추가로 호출하면 상위 요소로의 이벤트 버블링도 방지할 수 있다.
이러한 제어 메서드들은 이벤트 위임 패턴을 구현할 때 특히 중요하다. 부모 요소에 단일 리스너를 등록해도, 자식 요소에서 발생한 이벤트의 버블링을 필요에 따라 차단하거나 허용함으로써 복잡한 상호작용 로직을 효율적으로 관리할 수 있게 해준다.
6. 이벤트 위임
6. 이벤트 위임
이벤트 위임은 이벤트 버블링의 특성을 활용한 프로그래밍 패턴이다. 이 패턴은 여러 개의 하위 요소 각각에 개별적으로 이벤트 처리기를 등록하는 대신, 이들의 공통 상위 요소에 하나의 이벤트 처리기를 등록하여 하위 요소에서 발생하는 이벤트를 관리하는 방식이다. 이벤트가 발생한 특정 하위 요소는 이벤트 객체의 target 속성을 통해 식별할 수 있다.
이벤트 위임의 주요 장점은 코드의 효율성과 유지보수성 향상에 있다. 동적으로 추가되거나 제거되는 요소가 많은 경우, 각 요소마다 이벤트 리스너를 일일이 부착하거나 제거하는 복잡한 로직이 필요 없다. 또한, 상위 요소에 단 하나의 처리기만 등록하면 되므로 메모리 사용량이 줄어들고 초기화 성능이 개선된다. 이는 동적 콘텐츠를 다루는 현대 웹 애플리케이션에서 매우 유용한 기법이다.
일반적인 구현 예시로는 리스트 아이템(<li>) 목록이 있다. 각 아이템에 개별 클릭 이벤트를 등록하는 대신, 그들의 부모인 순서 없는 목록(<ul>) 요소에 하나의 addEventListener를 등록한다. 사용자가 특정 아이템을 클릭하면 이벤트는 버블링되어 부모 요소의 처리기로 전달되며, 처리기 내부에서 event.target을 검사하여 실제 클릭된 아이템을 찾아 그에 맞는 작업을 수행한다.
이 패턴은 마우스 이벤트나 키보드 이벤트 등 대부분의 버블링 이벤트에 적용 가능하다. 그러나 포커스 이벤트나 블러 이벤트 같이 버블링되지 않는 이벤트에는 사용할 수 없다는 점에 주의해야 한다. 또한, 상위 요소에 등록된 처리기가 너무 많은 하위 요소의 이벤트를 처리하게 되면, 처리기 내부의 조건 분기 로직이 복잡해질 수 있다.
7. 주의사항 및 모범 사례
7. 주의사항 및 모범 사례
7.1. 메모리 누수 방지 (이벤트 리스너 제거)
7.1. 메모리 누수 방지 (이벤트 리스너 제거)
이벤트 처리기를 등록한 요소가 더 이상 필요하지 않게 되어도, 처리기가 제거되지 않으면 메모리 누수가 발생할 수 있다. 이는 특히 단일 페이지 애플리케이션에서 페이지 전환 시 이전 뷰의 요소들이 제거되더라도, 해당 요소들에 바인딩된 이벤트 리스너가 여전히 메모리에 남아 참조를 유지하는 경우에 흔히 나타난다.
이러한 문제를 방지하기 위해서는 요소의 생명주기가 끝날 때 명시적으로 이벤트 리스너를 제거하는 것이 중요하다. addEventListener 메서드로 등록한 리스너는 removeEventListener 메서드를 사용하여 제거할 수 있다. 이때, 제거하려는 리스너 함수는 등록할 때 사용한 것과 동일한 참조여야 하므로, 익명 함수 대신 명명된 함수를 사용하는 것이 일반적인 모범 사례이다.
등록 방법 | 제거 방법 | 주의사항 |
|---|---|---|
|
| 제거 시 동일한 함수 참조와 이벤트 타입, 캡처 옵션 필요 |
DOM 프로퍼티 (예: |
| 간단하게 제거 가능 |
HTML 인라인 속성 | 속성 제거 또는 요소 자체 제거 | 일반적으로 요소가 DOM에서 제거되면 함께 해제됨 |
요소 자체를 DOM에서 완전히 제거하는 경우, 대부분의 현대 브라우저의 가비지 컬렉션 시스템은 연결된 이벤트 처리기를 자동으로 정리한다. 그러나 요소가 제거되기 전에 명시적으로 리스너를 제거하는 것은 더 확실한 메모리 관리와 예측 가능한 동작을 보장한다. 자바스크립트 프레임워크나 라이브러리를 사용할 경우, 컴포넌트 생명주기 메서드 내에서 이벤트 리스너를 정리하는 로직을 제공하는 경우가 많다.
7.2. 성능 고려사항
7.2. 성능 고려사항
이벤트 처리기의 성능을 고려할 때는 주로 이벤트 리스너의 수와 각 리스너의 실행 효율성에 초점을 맞춘다. 페이지에 수많은 DOM 요소에 개별적으로 리스너를 등록하면 메모리 사용량이 증가하고 초기 스크립트 실행 시간이 길어질 수 있다. 특히 동적으로 생성되는 요소가 많은 단일 페이지 애플리케이션에서는 이 문제가 두드러진다. 이러한 상황에서 이벤트 위임 패턴을 활용하면 상위 요소 하나에만 리스너를 등록하여 하위에서 발생하는 동일 유형의 이벤트를 처리할 수 있으므로, 리스너의 총 개수를 크게 줄이고 성능을 개선할 수 있다.
리스너 내부에서 수행되는 작업의 복잡성도 성능에 직접적인 영향을 미친다. 무거운 연산이나 레이아웃을 발생시키는 DOM 조작을 동기적으로 실행하면 메인 스레드를 차단하여 페이지의 반응성을 떨어뜨릴 수 있다. 이를 해결하기 위해, setTimeout이나 requestAnimationFrame을 사용하여 작업을 다음 이벤트 루프로 지연시키거나, Web Worker를 활용하여 무거운 계산을 별도의 스레드로 분리하는 방법이 있다. 또한, 이벤트 디바운싱과 스로틀링 기법은 스크롤이나 리사이즈 같이 짧은 시간에 연속해서 발생할 수 있는 이벤트의 처리 빈도를 제한하여 불필요한 함수 실행을 줄인다.
메모리 누수 방지는 장기적인 성능 유지에 필수적이다. addEventListener로 등록한 리스너는 요소가 DOM에서 제거되더라도 자동으로 해제되지 않는다. 따라서 더 이상 필요하지 않은 요소, 특히 동적으로 생성 후 삭제되는 요소에 연결된 리스너는 반드시 removeEventListener를 호출하여 명시적으로 제거해야 한다. 그렇지 않으면 가비지 컬렉션의 대상이 되지 않아 메모리가 계속 점유되는 누수가 발생한다. 프레임워크나 라이브러리를 사용할 경우, 해당 도구의 생명주기 메서드를 활용하여 컴포넌트가 사라질 때 리스너를 정리하는 것이 일반적인 모범 사례이다.
