자바스크립트 클래스 안에서 이벤트리스너를 등록하고, 그 콜백 함수 안에서 this를 사용하려면 주의해야 한다.
아래는 board 엘리먼트의 자식 엘리먼트를 모두 선택해 각각에 이벤트리스너를 등록하는 메서드를 구현한 것이다.
export default class BoardHandler{
#gameManager;
/*
...
*/
#CLASS_NAME_BOARD_CHILD= ".board__child";
$allChildren = document.querySelectorAll(this.#CLASS_NAME_BOARD_CHILD);
#initializeBoardElement() {
this.$allChildren.forEach(($child) => ($child.textContent = ""));
this.$allChildren.forEach(($child) =>
$child.addEventListener(
"click",
this.#handleClickBoardSquare
)
);
}
#handleClickBoardChild() {
console.log(this); // <td> ... HTML Element
this.mark() // Error
}
mark() {
/* ... */
}
/*
...
*/
}
클래스 안에서 메서드를 작성할 때 this는 자연스럽게 해당 클래스의 인스턴스를 가리킨다.
하지만 이벤트리스너의 콜백함수로 호출될 때, 콜백함수 안에서 this는 클래스의 인스턴스를 가리키는 것이 아니다.
이 this는 이벤트가 일어난 HTML 엘리먼트를 가리킨다.
따라서 나는 이 상황을 아래와 같이 해결했다. 이벤트리스너를 부착할 때 콜백함수에 bind
메서드로 콜백함수가 호출될 때 this로 사용할 객체로 this(BoardHandler의 인스턴스), 그 다음 인자로 $child 엘리먼트를 전달했다.
이렇게 하면 문제 없이 의도한 대로 잘 실행된다.
export default class BoardHandler{
#gameManager;
/*
...
*/
#CLASS_NAME_BOARD_CHILD= ".board__child";
$allChildren = document.querySelectorAll(this.#CLASS_NAME_BOARD_CHILD);
#initializeBoardElement() {
this.$allChildren.forEach(($child) => ($child.textContent = ""));
this.$allChildren.forEach(($child) =>
$child.addEventListener(
"click",
this.#handleClickBoardSquare.bind(this, $child)
)
);
}
#handleClickBoardChild($child) {
const index = $child.id;
const activePlayer = this.#gameManager.getActivePlayer();
const type = activePlayer.getType();
this.mark($child, index, type);
}
/*
...
*/
}
물론 다른 방법으로 고차함수를 활용할 수도 있다. 하지만 이번 상황에서는 해당 이벤트리스너의 콜백함수가 기억해야 할 객체가 매번 변동되지 않고 일정해서 그럴 필요가 없겠다고 판단했다.
'프로그래밍-학습기록 > Javascript' 카테고리의 다른 글
배열을 같은 값으로 초기화할 때 하드코딩보다 Array(number).fill(something)를 사용하자. (0) | 2021.03.12 |
---|---|
Array 메소드(filter, find 등)의 반환 값을 잘 알아두자. (0) | 2021.03.11 |
초간단 팁: javascript parcel로 빌드할 때 class property, private mehtods 사용하는 방법 (0) | 2021.03.09 |
고차함수를 활용한 이벤트리스너 부착과 제거 (0) | 2021.03.08 |
자바스크립트에서 '없음'을 나타내는 두 가지 방법, undefined와 null (0) | 2021.02.21 |