html에서 각각의 태그로 감싸진 박스 모델에 식별자를(id, className, tagName)을 설정해주면 자바스크립트에서 손쉽게 해당 DOM을 선택할 수 있다. 여기서 DOM(Document Object Model)이란 문서 객체 모델로, 각 태그에 대한 정보를 가지고 있는 js객체를 의미한다.
DOM을 선택하는 방법은 여러가지가 있다. 대표적으로 getElementBy~
와 querySelector
를 사용할 수 있는데 사용법은 다음과 같다.
document.getElementById("{id-name}");
document.getElementsByClassName("{class-name}");
document.querySelector("#{id-name}");
document.querySelectorAll(".{class-name}");
querySelector
를 이용하면 css 선택자를 통해서 좀 더 융통성있고 가독성있게 DOM을 선택할 수 있어서 모던 자바스크립트에서는 많이 쓰인다.
이벤트란 브라우저 상에서 일어나는 어떤 사건을 의미한다.
cached
: 애플리케이션이 캐시될 때load
: 웹 페이지의 로드가 완료되었을 때unload
: 웹 페이지가 unload 될 때 (새로운 페이지를 요청한 경우)error
: 브라우저가 자바스크립트 오류를 만났거나 리소스 로드를 실패했을 때resize
: 브라우저 창의 크기를 조정했을 때scroll
: 사용자가 페이지를 위아래로 스크롤 할 때focus
: 엘리먼트가 포커스를 받았을 때(버블링하지 않음)click
: 엘리먼트를 클릭 할 때
이벤트 리스너란, 말 그대로 특정 이벤트가 발생했을 때 그것을 감지하는 역할을 하는 것을 말한다. 원래는 더 상위 개념으로 이벤트 핸들러라는 것이 있는데, 이벤트를 감지하고 다루는 역할을 한다. 하지만 최근에는 이벤트 리스너 방식을 주로 사용한다.
이벤트 리스너 방식으로 버튼 클릭 시 카운트를 증가시키는 이벤트를 등록하면 다음과 같다.
function onIncreaseCountHandler() {
// 이벤트 처리 로직
}
const $increaseButton = document.querySelector("#increase-btn");
$increaseButton.addEventListener('click', onIncreaseCountHandler);
// onIncreaseCountHandler 함수를 함수명 가지고 바인딩 시켰다.
// 그 이유는 () 를 넣을 경우 이벤트를 기다리지 않고 바인딩 되는 동시에 함수가 실행되기 때문이다.
현재는 함수의 매개변수가 없기 때문에 함수명만 가지고 바인딩을 시킬 수 있지만 만약, 매개변수가 존재하는 함수의 경우에는 아래와 같이 익명함수로 작성해야 한다.
const $increaseButton = document.querySelector("#increase-btn");
$increaseButton.addEventListener('click', function() {
onIncreaseCountHandler(params)
});
자바스크립트는 이벤트 기반의 언어이기 때문에, 하나의 이벤트를 실행하기 위해서 이전 이벤트가 선행되어야 하는 경우가 생긴다.
콜백 함수 기법은 예측 불가능한 사용자의 수 많은 이벤트 환경 속에서, 비동기적인 처리를 할 수 있는 가장 오래된 자바스크립트 매커니즘이라고 할 수 있다.
모던 자바스크립트에서는 콜백함수의 진화형인 promise, async 등을 사용해서 더 편리하게 이벤트를 비동기적으로 관리할 수 있다.
위에서 살펴본 이벤트 리스너에 등록된 onIncreaseCountHandler 함수가 바로 콜백함수라고 할 수 있다. 코드 상으로는 스크립트의 상단에 적혀있지만, 순서대로 호출되는 것이아닌 이벤트가 온전히 발생하고 나서야 실행되기 때문이다.
DOM에 대해 이벤트를 연결했다면 event라는 이름으로 이벤트 객체를 매개변수로 전달할 수 있다.
이벤트 객체에는 이벤트에 대한 정보와, 이벤트를 조작하는 메서드들이 내장되어 있다.
event.target
을 사용하면 이벤트가 발생한 tag 정보를 알 수 있다.
대표적인 event 메서드로는 preventDefault
와 stopPropagation
, stopImmediatePropagation
이 있다.
preventDefault
메소드는 태그의 기본 동작(ex, a 태그는 클릭 시 링크이동, form 태그은 폼 내용 전송)을 하지 않게 막아준다. stopPropagation
은 이벤트가 버블링되지 않도록 하고, stopImmediatePropagation
은 버블링을 막음과 동시에 같은 이벤트의 다른 리스너도 실행되지 않도록 한다. 만약 여러 개의 클릭 이벤트를 동시에 연결한 경우, stopPropagation
으로 클릭 이벤트를 막아도 다른 클릭 이벤트는 실행된다. 하지만 stopImmediatePropagation
으로 클릭 이벤트를 막으면 부모에게는 어떠한 이벤트도 버블링되지 않으면서 다른 클릭 이벤트도 실행되지 않는다.
이벤트가 발생하는 순서를 이벤트 흐름(event flow)이라고 하며, 이벤트가 흐르는 방식은 다음의 두 가지가 있다.
버블링이란 자식의 이벤트가 부모에게도 전파 되는 것을 의미한다. 반대로 이벤트 캡처링이란 부모의 이벤트가 자식에게 전파되는 것을 의미한다.
이벤트 리스너를 지정하는 요소가 많으면 많을수록 페이지의 실행 속도는 느려진다. 그래서 앞서 살펴본 이벤트의 흐름을 이용하면 효과적으로 이벤트를 관리할 수 있다. 이벤트는 target 엘리먼트를 포함하고 있는 부모 요소에도 영향을 미치기 때문에 자식 요소를 포함하는 부모 요소에 이벤트 리스너를 지정하여 관리한다.
즉, 이벤트 리스너가 실행할 작업을 부모 요소에게 위임(Delegation)하는 것이 이벤트 위임이다.
// 장점
동적으로 추가되는 요소들에도 동작한다.
- DOM트리에 새로운 요소를 추가하더라도 이벤트에 대한 처리는 부모 요소에게 위임되었기 때문에 새로운 요소에 이벤트 핸들러를 다시 지정할 필요가 없다.
코드의 간결
- 함수를 많이 작성할 필요가 없으며 DOM과 코드간의 연결이 간소해져 결과적으로 유지보수에 도움이 된다.
동적으로 리스트를 추가하는 곳에 이벤트 위임을 설정하면, 리스트가 추가될 때마다 이벤트 리스너를 지정해 줄 필요없이 부모 요소에게 이벤트 리스너를 등록함으로써 쉽게 이벤트를 관리한다. 아레 예시 코드를 보자.
// html
<ul id="parent-list">
<li id="item1">Item 1</li>
<li id="item2">Item 2</li>
<li id="item3">Item 3</li>
</ul>
// js
document.querySelector("#parent-list").addEventListener("click", function (e) {
if (e.target && e.target.nodeName == "LI") {
console.log(`List item ${e.target.id} was clicked!`);
}
});
BOM(Browser Object Model)은 웹 브라우저 환경의 다양한 기능을 객체처럼 다루는 모델을 가리킨다. BOM의 역할은 웹 브라우저의 버튼, URL 주소 입력 창, 타이틀 바 등 웹브라우저 윈도우 및 웹페이지의 일부분을 제어할 수 있게끔 하는 것이다.
아래는 대표적인 BOM 객체들이다.
1) window
: Global Context. 브라우저 창 객체
2) screen
: 사용자 환경의 디스플레이 정보 객체
3) location
: 현재 페이지의 url을 다루는 객체
4) navigator
: 웹브라우저 및 브라우저 환경 정보 객체
5) history
: 현재의 브라우저가 접근했던 URL history
BOM을 통해서 사용자에게 alert
, confirm
, prompt
을 사용해서 액션을 제어할 수 있다.