this 는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수입니다.
this 를 통해서 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있습니다.
함수를 호출하면 this 가 암묵적으로 함수 내부에 전달됩니다.
this 가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 의해 동적으로 결정됩니다.
const person = {
name: 'Lee',
getName() {
return this.name;
}
};
console.log(person.getName()); // Lee

const anotherPerson = {
name: 'Kim'
};
// getName 메서드를 anotherPerson 객체의 메서드로 할당
anotherPerson.getName = person.getName;
console.log(anotherPerson.getName()); // Kim

자바스크립트에서 이벤트 핸들러 내부의 this 키워드가 가리키는 대상은 함수가 어떻게 정의되고 호출되느냐에 따라 다릅니다. 이 글에서는 다양한 방식으로 이벤트 핸들러를 정의했을 때 this가 어떻게 동작하는지 설명합니다.
HTML 어트리뷰트로 이벤트 핸들러를 설정할 때, 함수 내부의 this는 전역 객체(window)를 가리킵니다.
<!DOCTYPE html>
<html>
<body>
<button onclick="handleClick()">Click me</button>
<script>
function handleClick() {
console.log(this); // window
}
</script>
</body>
</html>
위 예제에서 handleClick 함수는 이벤트 핸들러로 호출되지만, this는 전역 객체 window를 가리킵니다. 이는 이벤트 핸들러가 일반 함수로 호출되기 때문입니다.
이벤트 핸들러에 this를 전달하여 이벤트를 바인딩한 DOM 요소를 가리키도록 할 수 있습니다.
<!DOCTYPE html>
<html>
<body>
<button onclick="handleClick(this)">Click me</button>
<script>
function handleClick(button) {
console.log(button); // 이벤트를 바인딩한 button 요소
console.log(this); // window
}
</script>
</body>
</html>
위 예제에서 handleClick 함수에 this를 전달하여 button 요소를 가리키게 했습니다. 하지만 함수 내부에서 this는 여전히 전역 객체 window를 가리킵니다.
이 두 방식 모두 이벤트 핸들러 내부의 this는 이벤트를 바인딩한 DOM 요소를 가리킵니다.
<!DOCTYPE html>
<html>
<body>
<button class="btn1">0</button>
<button class="btn2">0</button>
<script>
const $button1 = document.querySelector('.btn1');
const $button2 = document.querySelector('.btn2');
// 이벤트 핸들러 프로퍼티 방식
$button1.onclick = function (e) {
console.log(this); // $button1
console.log(e.currentTarget); // $button1
console.log(this === e.currentTarget); // true
++this.textContent;
};
// addEventListener 메서드 방식
$button2.addEventListener('click', function (e) {
console.log(this); // $button2
console.log(e.currentTarget); // $button2
console.log(this === e.currentTarget); // true
++this.textContent;
});
</script>
</body>
</html>
이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드 방식을 사용하면 this는 이벤트를 바인딩한 DOM 요소를 가리킵니다.
화살표 함수로 정의한 이벤트 핸들러 내부의 this는 상위 스코프의 this를 가리킵니다. 따라서 이벤트를 바인딩한 DOM 요소를 가리키지 않습니다.
<!DOCTYPE html>
<html>
<body>
<button class="btn1">0</button>
<button class="btn2">0</button>
<script>
const $button1 = document.querySelector('.btn1');
const $button2 = document.querySelector('.btn2');
// 이벤트 핸들러 프로퍼티 방식
$button1.onclick = e => {
console.log(this); // window
console.log(e.currentTarget); // $button1
console.log(this === e.currentTarget); // false
++this.textContent;
};
// addEventListener 메서드 방식
$button2.addEventListener('click', e => {
console.log(this); // window
console.log(e.currentTarget); // $button2
console.log(this === e.currentTarget); // false
++this.textContent;
});
</script>
</body>
</html>
화살표 함수는 자신만의 this 바인딩을 가지지 않고 상위 스코프의 this를 가리키기 때문에, 위 예제에서 화살표 함수 내부의 this는 window 객체를 가리킵니다.
클래스에서 이벤트 핸들러를 바인딩할 때는 this에 주의해야 합니다. 이벤트 핸들러 내부의 this가 클래스 인스턴스를 가리키도록 하려면 bind 메서드를 사용해 바인딩해야 합니다.
<!DOCTYPE html>
<html>
<body>
<button class="btn">0</button>
<script>
class App {
constructor() {
this.$button = document.querySelector('.btn');
this.count = 0;
// increase 메서드를 이벤트 핸들러로 등록
this.$button.onclick = this.increase.bind(this);
}
increase() {
this.$button.textContent = ++this.count;
}
}
new App();
</script>
</body>
</html>
위 예제에서 increase 메서드는 클래스 인스턴스를 가리키도록 bind 메서드를 사용해 바인딩합니다. 이를 통해 클래스 인스턴스의 this가 이벤트 핸들러 내부에서도 유지됩니다.
이처럼 자바스크립트에서 이벤트 핸들러 내부의 this는 함수가 정의되고 호출되는 방식에 따라 달라집니다. 이를 올바르게 이해하고 사용함으로써 예측 가능한 코드를 작성할 수 있습니다.