자바스크립트에서 this 는 모든 실행 컨텍스트마다 생성되는 특수한 변수로, 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수다.
자바나 C++ 같은 클래스 기반 언어에서 this는 언제나 클래스가 생성하는 인스턴스를 가리킨다. 하지만 자바스크립트에서는 this가 가리키는 값은 함수가 실제로 호출이 될 때 동적으로 바인딩 된다. 또한 strict mode도 this 바인딩에 영향을 준다.
일반함수로 정의한 메서드 호출시 this는 메서드를 호출한 객체를 가리킨다.
const sunny = {
name : 'Sunny',
year : '1994',
calcAge: function(){
return 2037 - this.year; // this.year: 1994
}
}
const age = sunny.calcAge();
console.log(age); // 43
strict mode 사용시, 일반함수 호출시 내부의 this가 가리키는 것은 undefined다.
'use strict'
function calcAge(){
return 2037 - this.year; // this.year: undefined
}
calcAge();
strict mode를 사용하지 않으면 일반함수 호출시 내부의 this가 전역 객체, 즉 브라우저 환경이라면 window 객체를 가리키게 된다.
function calcAge(){
return 2037 - this.year; // this.year: window 객체(브라우저 환경)
}
calcAge();
화살표 함수는 함수 자체의 this 바인딩을 가지지 않는다. 화살표 함수 내부에서 this를 참조하면 상위 스코프 체인을 통해 상위 스코프의 this를 참조한다.
콜백함수 내부의 this 문제
화살표 함수가 자체의 this 바인딩을 갖지 않는 것은, 콜백 함수 내부의 this가 외부 함수의 this와 다르기 때문에 발생하는 문제를 해결하기 위해 의도적으로 설계된 것이다.
'use strict'
const sunny = {
name: 'Sunny',
log: function(...hobby) {
hobby.forEach(function(v){ // 일반함수로써 콜백함수 호출
console.log(`I'm ${this.name}. My hobby is ${v}`)
});
}
}
sunny.log('coding', 'reading');
// TypeError: Cannot read properties of undefined
// (reading 'name')
위 log 메서드 내 forEach문의 콜백 함수는 일반함수로써 호출되었기 때문에 this가 undefined를 가리키게 된다.
Es6이전에는 이런 문제를 해결하기 위해 Function.prototype.bind 메서드를 사용하는 등의 방법으로 this를 직접 바인딩했다.
es6 이후로는, 화살표 함수를 콜백함수로 사용하면 이런 문제가 해결된다.
const sunny = {
name: 'Sunny',
log: function(...hobby) {
hobby.forEach((v) => {
console.log(`I'm ${this.name}. My hobby is ${v}`)
});
}
}
sunny.log('coding', 'reading');
// I'm Sunny. My hobby is coding
// I'm Sunny. My hobby is reading
화살표 함수로 메서드를 정의하지 말자
아래의 경우 sayHi 프로퍼티에 할당한 화살표 함수 내부의 this는 메서드를 호출한 객체인 person이 아니라 상위 스코프인 전역의 this를 가리킨다.
const sunny = {
name: 'Sunny',
sayHi: () => {
console.log(`Hi I am ${this.name}`);
}
}
sunny.sayHi();
메서드를 정의할 때는 아래처럼 es6 메서드 축약 표현으로 정의된 es6 메서드를 사용하는 것이 좋다.
const sunny = {
name: 'Sunny',
sayHi(){
console.log(`Hi I am ${this.name}`);
}
}
sunny.sayHi();
일반 함수로 정의한 이벤트 핸들러 함수 내에서 사용하는 this는 호출시 이벤트 핸들러 함수가 등록된 DOM 요소와 바인딩 된다.
document.querySelector("#button").addEventListener(
"click",
function(){
console.log(this);
// <button id="button" type="button">버튼</button>
}
)