TIL] Deep Dive-Event(2)
🌼 40.5 이벤트 객체
이벤트가 발생하면 이벤트에 관련된 다양한 정보를 담고 있는 객체
가 동적으로 생성되며 이렇게 생성된 객체는 이벤트 핸들러의 첫번째 인수로 전달
되는데, 이 객체를 전달받으려면 매개변수를 명시적으로 선언해야 한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<!--이벤트 핸들러 어트리뷰트 방식의 경우 매개변수 이름이 event가 아니면 이벤트 객체를 전달받지 못한다.-->
<body onclick="showCoords(event)">
<p>클릭한 곳의 좌표가 표시됩니다.</p>
<em class="message"></em>
<script>
const $msg = document.querySelector(".message");
function showCoords(e) {
$msg.textContent = `clientX: ${e.clientX}, clientY: ${e.clientY}`;
}
</script>
</body>
</html>
🌼 40.5.2 이벤트 객체의 공통 프로퍼티
Event 인터페이스의 이벤트 관련 프로퍼티는 모든 이벤트 객체가 상속받는 공통 프로퍼티이다.
-
eventPhase
: 이벤트 전파 단계를 나타낸다. (0: 이벤트 없음, 1: 캡처링 단계, 2: 타깃 단계, 3: 버블링 단계) -
target
: 이벤트를 발생시킨 객체를 나타낸다. -
currentTarget
: 이벤트 핸들러가 바인딩된 DOM 요소를 나타낸다. -
cancelable
: preventDefault 메서드를 호출하여 이벤트의 기본 동작을 취소할 수 있는지 여부를 나타댄다. (false: 취소할 수 없다.)
🌼 40.6 이벤트 전파
DOM 요소 노드에서 발생한 이벤트는 DOM 트리를 통해 전파(propagation)
된다. 이를 이벤트 전파라고 한다. 이벤트 전파는 전파되는 방향에 따라 3가지로 구분할 수 있다. 이벤트 객체는 window에서 시작해서 이벤트 타깃을 향해 전파되는데 캡처링-타깃-버블링 순서이다.
이벤트 핸들러 어트리뷰트/프로퍼티 형태로 핸들러를 등록한 경우에는 타깃과 버블링 단계의 이벤트만 캐치할 수 있다. 이벤트 핸들러 메서드 방식은 세번째 인수를 true로 설정하면 캡처링 단계의 이벤트를 선별적으로 캐치할 수 있다.
-
캡처링 단계
: 이벤트가 상위 요소에서 하위 요소로 전파 -
타깃 단계
: 이벤트가 이벤트 타깃에 도달 -
버블링 단계
: 이벤트가 하위 요소에서 상위 요소로 전파
🌼 40.7 이벤트 위임
이벤트 위임(delegation)
은 여러 개의 하위 DOM 요소에 각각 이벤트 핸들러를 등록하는 대신 하나의 상위 돔 요소에 이벤트 핸들러를 등록하여 하위 요소의 이벤트를 모두 핸들링하는 방법을 말한다. 이 방법을 사용할 경우, 하위에 동적으로 추가된 요소에 대해서도 동일한 방식으로 이벤트를 핸들링할 수 있다.
-
이벤트를 실제 발생시킨 요소가 개발자가 기대한 DOM 요소가 아닐 수 있기 때문에 이벤트 타깃을 검사할 필요가 있다.
- Element.prototype.matches('선택자')를 사용하면 특정 노드를 탐색가능한지 확인할 수 있다.
-
이벤트를 상위에 바인딩할 경우, 이벤트 객체의 target 프로퍼티와 currentTarget 프로퍼티가 다를 수 있다.
🌼 40.8 DOM 요소의 기본 동작 조작
-
이벤트 객체의
preventDefault
메서드는 DOM 요소의 기본 동작을 중단시킨다.- form 요소의 경우, submit 동작이 실행될 경우, 페이지가 자동적으로 refresh되는데 이러한 기본 동작을 중단시킬 수 있다.
-
이벤트 객체의 stopPropagation 메서드는 이벤트 전파를 중지시킨다.
stopPropagation
은 하위 DOM 요소의 이벤트를 개별적으로 처리해야하는 경우에 사용할 수 있다.
🌼 40.9 이벤트 핸들러 내부의 this
- 이벤트 핸들러 어트리뷰트 방식의 경우, 이벤트 핸들러에 인해 일반 함수로 호출되므로 함수 내부의 this는 전역 객체 window를 가리킨다. 단, 이벤트 핸들러를 호출할 때 인수로 전달한 this는 이벤트를 바인딩한 DOM 요소를 가리킨다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<!-- 이벤트 핸들러를 호출할 때 인수로 전달한 this는 이벤트를 바인딩한 DOM 요소이다.
이벤트 어트리뷰트 우측의 내용은 onclick 함수 body에서 실행될 구문이다.
즉시 실행 함수(IIFE) 형태가 아닌 경우 console.log(this)는 실행되지 않는다.-->
<button class="button1" onclick="(() => console.log(this))(); handleClick1();">0</button>
<!--이벤트 핸들러의 첫 번째 매개변수의 이름이 event로 암묵적으로 명명된다.-->
<button class="button2" onclick="handleClick2(event)">0</button>
<button class="button3">0</button>
<button class="button4">0</button>
<script>
// 일반함수로 호출되는 함수 내부의 this는 window이다.
function handleClick1() {
console.log(this);
}
// 이벤트 핸들러를 통해 전달받은 인자, e는 이벤트 객체이다.
// 화살표 함수는 this를 바인딩하지 않고 상위 스코프의 this를 가리킨다.
// this는 window이다.
const handleClick2 = (e) => {
console.log(e);
console.log(this);
};
const $button3 = document.querySelector(".button3");
const $button4 = document.querySelector(".button4");
// 이벤트를 바인딩한 DOM 요소가 this이다.
$button3.onclick = function () {
console.log(this);
};
// 화살표 함수는 this를 바인딩하는 과정이 제외됨,
// 접근하고자하면 스코프체인상 가장 가까운 this에 접근하여 반환한다.
// 화살표 함수는 콜백 함수 내에서 this가 전역객체를 가리키는 문제를 해결하기 위한 대안으로 나타났다.
$button4.addEventListener("click", () => {
console.log(this);
});
// console.log(1)은 return 값이 undefined이다.
// console.log(1)이 바인딩 과정에서 실행은되나 실제로 바인딩된 함수는 없다.
$button4.addEventListener("click", console.log(1));
</script>
</body>
</html>
-
이벤트 핸들러 프러터티와 이벤트 핸들러 메서드 방식의 경우, 이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가리킨다.
-
화살표 함수로 정의한 이벤트 핸들러 내부의 this는 상위 스코프의 this를 가리킨다. 화살표 함수는 함수 자체의 this 바인딩을 갖지 않는다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button>0</button>
</body>
<script>
const $button = document.querySelector("button");
// this는 이벤트를 바인딩한 DOM 요소를 가리킨다. <button>0</button>
$button.addEventListener("click", function (e) {
console.log(this);
});
// this는 상위 스코프의 this를 가리킨다. window
$button.addEventListener("click", (e) => {
console.log(this);
});
</script>
</html>
class에서 이벤트 핸들러를 바인딩할 경우
, 일반 함수의 this는 class가 생성할 인스턴스를 가리키지 않는다. 이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가리키키 때문에 별도로 this(생성할 인스턴스)를 bind 과정이 필요하다. 단, 화살표 함수의 경우는 함수가 인스턴스의 메서드로서 동작하기 때문에 별도의 bind 과정이 필요없다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<button class="btn1">0</button>
<button class="btn2">0</button>
<button class="btn3">0</button>
<script>
class App {
constructor() {
this.$button1 = document.querySelector(".btn1");
this.$button2 = document.querySelector(".btn2");
this.$button3 = document.querySelector(".btn3");
this.count1 = 0;
this.count2 = 0;
this.count3 = 0;
this.$button1.onclick = this.increase1;
// increase2 메서드 내부의 this가 클래스가 생성할 인스턴스를 가리키도록 한다.
this.$button2.onclick = this.increase2.bind(this);
this.$button3.onclick = this.increase3;
}
increase1() {
// 이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가리킨다.
// 여기서 this는 this.$button 이다.
console.log("increase1");
this.$button1.textContent = ++this.count1;
}
increase2() {
// this는 클래스가 생성할 인스턴스를 가리킨다.
console.log("increase2");
this.$button2.textContent = ++this.count2;
}
// increase3는 프로토 타입의 메서드가 아니라 인스턴스의 메서드로서 동작한다.
increase3 = () => {
// 화살표 함수의 this는 상위 스코프의 this를 가리킨다.
console.log("increase3");
this.$button3.textContent = ++this.count3;
};
}
new App();
</script>
</body>
</html>
출처: 모던 자바스크립트 Deep Dive-이웅모
Author And Source
이 문제에 관하여(TIL] Deep Dive-Event(2)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@link717/TIL-Deep-Dive-Event2저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)