js로 테트리스를 만들던 중 흥미로운 에러가 있었다.
export default class Controller {
service: Service;
constructor(service: Service) {
this.service = service;
document.addEventListener("keydown", this.handleKeyDown);
}
private handleKeyDown(event: KeyboardEvent) {
switch (event.key) {
case "ArrowLeft":
event.preventDefault();
this.service.moveBlockLeft();
break;
...
}
}
}
웹 페이지에서 키 입력이 있을 경우 케이스에 맞게 블럭을 움직이는 로직인데 키를 입력해도 화면에서 블럭이 움직이지 않는다.
Service
클래스 테스트는 잘 통과했는데?
TypeError: Cannot read properties of undefined (reading 'moveBlockLeft')
콘솔에 위와 같은 에러가 찍혀있다
분명히 Service
클래스에는 해당 메서드가 있는데?
쳇지피티가 문제를 해결해 주었다.
쳇지피티는 바인드 메서드를 알려주었다.
MDN의 bind() 문서 예시를 보면 다음과 같은 글이 있다.
초보 JavaScript 프로그래머로서 흔한 실수는 객체로부터 메소드를 추출한 뒤 그 함수를 호출할 때, 원본 객체가 그 함수의 this로 사용될 것이라 기대하는 겁니다.
아니 누구나 그렇게 기대할거 같은데?
특별한 조치가 없으면, 대부분의 경우 원본 객체는 손실됩니다. 원본 객체가 바인딩되는 함수를 생성하면, 이러한 문제를 깔끔하게 해결할 수 있습니다.
나 역시 특별한 조치가 없었다.
constructor(service: Service) {
this.service = service;
this.handleKeyDown = this.handleKeyDown.bind(this);
document.addEventListener("keydown", this.handleKeyDown);
}
위 코드처럼 this가 항상 이 클래스를 가리키도록 바인딩 해줘야 한다.
그럼 this가 무엇을 가리키고 있었는지 궁금해서콘솔에 찍어보니 `document`가 나왔다...
분명 주소를 참조해서 메서드를 호출할텐데 왜 this가 바뀌지?
대부분의 경우 this의 값은 함수를 호출한 방법에 의해 결정됩니다.
javascript에서는 그렇다고 한다.
문서를 읽다가 this가 어떻게 동작하는지 살짝 감이 잡혀서 나만의 예시코드를 한번 만들어 봤다.
this.x = 100;
function getX() {
return this.x;
}
console.log(getX());
// 100
const iHaveX = {
x: 1
}
iHaveX.getX = getX;
console.log(iHaveX.getX());
// 1
출처 - MDN - this , MDN - bind()
javascript 형변환 (0) | 2024.12.16 |
---|---|
javascript 게임 벽돌깨기 (0) | 2024.08.24 |
javascript callback (0) | 2024.07.11 |
javascript 2차원 배열 순환속도 for loop, forEach, map (0) | 2024.06.20 |
JavaScript api 포커스 해제 blur() (0) | 2024.04.25 |