this란?
this는 자바스크립트에서 현재 실행 중인 컨텍스트의 객체를 참조하는 특별한 식별자입니다. this의 값은 함수가 호출되는 방식에 따라 동적으로 결정되는데, 일반 함수에서는 전역 객체를, 메서드로 호출될 때는 해당 메서드를 소유한 객체를, 화살표 함수에서는 상위 스코프의 this 값을 참조합니다. 또한 call(), apply(), bind() 메서드를 통해 this의 바인딩을 명시적으로 변경할 수 있어 유연한 객체 지향 프로그래밍을 가능하게 합니다.
this 바인딩이란?
this 바인딩은 this 키워드가 실제로 가리키는 대상을 결정하는 과정입니다. JavaScript에서 this는 코드가 작성된 시점이 아닌, 함수가 실행되는 시점에 바인딩이 결정됩니다. 즉, 동일한 함수라도 어떻게 호출되느냐에 따라 this가 가리키는 대상이 달라질 수 있습니다.
this의 동적 바인딩
JavaScript에서 this는 함수가 호출되는 방식에 따라 동적으로 바인딩됩니다. 다음은 주요한 this의 바인딩 패턴입니다
1. 일반 함수 호출
function show() {
console.log(this);
}
show(); // Window 객체 (비엄격 모드)
// undefined (엄격 모드)
일반 함수로 호출할 경우 this는 전역 객체(window)에 바인딩됩니다. 단, 엄격 모드에서는 undefined가 됩니다.
2. 메서드 호출
const user = {
name: 'John',
sayHi() {
console.log(`Hi, ${this.name}`);
}
};
user.sayHi(); // "Hi, John"
객체의 메서드로 호출될 경우 this는 해당 메서드를 소유한 객체에 바인딩됩니다.
3. 화살표 함수
const user = {
name: 'John',
regularFn() {
console.log(this.name); // 'John'
// 일반 함수
setTimeout(function() {
console.log(this.name); // undefined (this가 window)
}, 100);
// 화살표 함수
setTimeout(() => {
console.log(this.name); // 'John' (외부 스코프의 this를 사용)
}, 100);
}
};
화살표 함수는 자신만의 this를 가지지 않고, 외부 스코프의 this를 그대로 사용합니다.
4. 생성자 함수 호출
function User(name) {
this.name = name;
this.sayHi = function() {
console.log(`Hi, ${this.name}`);
};
}
const user = new User('John');
user.sayHi(); // "Hi, John"
new 키워드로 생성자 함수를 호출하면 this는 새로 생성되는 객체에 바인딩됩니다.
5. 이벤트 핸들러
button.addEventListener('click', function() {
console.log(this); // 버튼 엘리먼트
});
이벤트 핸들러로 사용될 경우 this는 이벤트가 발생한 요소에 바인딩됩니다.
6. call, apply, bind를 통한 명시적 바인딩
이 메서드들을 사용하면 this를 명시적으로 지정할 수 있습니다:
function introduce(age, job) {
console.log(`I'm ${this.name}, ${age} years old ${job}`);
}
const person = {
name: 'John'
};
// call: 인자를 쉼표로 구분하여 전달
introduce.call(person, 30, 'developer');
// "I'm John, 30 years old developer"
// apply: 인자를 배열로 전달
introduce.apply(person, [30, 'developer']);
// "I'm John, 30 years old developer"
// bind: 새로운 함수를 반환, 나중에 실행 가능
const boundIntroduce = introduce.bind(person);
boundIntroduce(30, 'developer');
// "I'm John, 30 years old developer"
차이점
call
: 함수를 즉시 실행, 인자를 쉼표로 구분하여 전달apply
: 함수를 즉시 실행, 인자를 배열로 전달bind
: 함수를 즉시 실행하지 않고 this가 바인딩된 새로운 함수를 반환
this 바인딩의 특징
- 동적 바인딩: this는 함수가 호출되는 시점에 바인딩이 결정됩니다.
- 문맥 의존성: 동일한 함수라도 호출 방식에 따라 this가 가리키는 대상이 달라집니다.
- 화살표 함수의 특별한 this: 화살표 함수는 자신의 this를 생성하지 않고 외부 스코프의 this를 사용합니다.
- 명시적 제어 가능: call, apply, bind 메서드를 통해 this 바인딩을 명시적으로 제어할 수 있습니다.
콜백 함수의 this 바인딩 문제와 해결
문제 상황
const user = {
name: 'John',
friends: ['Alice', 'Bob'],
printFriends() {
this.friends.forEach(function(friend) {
console.log(`${this.name}의 친구: ${friend}`);
});
}
};
user.printFriends();
// "undefined의 친구: Alice"
// "undefined의 친구: Bob"
이 코드가 의도대로 동작하지 않는 이유는 forEach의 콜백 함수 내부에서 this가 전역 객체를 가리키기 때문입니다.
전통적인 해결 방법
const user = {
name: 'John',
friends: ['Alice', 'Bob'],
printFriends() {
const that = this; // this를 변수에 저장
this.friends.forEach(function(friend) {
console.log(`${that.name}의 친구: ${friend}`);
});
}
};
user.printFriends();
// "John의 친구: Alice"
// "John의 친구: Bob"
화살표 함수를 사용한 해결
const user = {
name: 'John',
friends: ['Alice', 'Bob'],
printFriends() {
this.friends.forEach(friend => {
console.log(`${this.name}의 친구: ${friend}`);
});
}
};
user.printFriends();
// "John의 친구: Alice"
// "John의 친구: Bob"
화살표 함수를 사용하면 효과적인 이유:
- 렉시컬 스코프: 화살표 함수는 자신만의 this를 생성하지 않고 외부 스코프(이 경우 printFriends 메서드)의 this를 그대로 사용합니다.
- 코드 간결성: 별도의 변수 선언 없이 외부 스코프의 this에 직접 접근할 수 있습니다.
- 실수 방지: this 바인딩 관련 실수를 줄일 수 있습니다.
'DEV > FE' 카테고리의 다른 글
Tanstack Table 쓰기 전에 공식문서 읽어보기(번역과 함께) (0) | 2025.04.04 |
---|---|
[FE] 브라우저와 렌더링 (0) | 2025.02.07 |
[FE] 자바스크립트 비동기 개념 정리 하기 (0) | 2025.01.30 |
[FE] 쉽게 이해하는 Vitest 주요 기능 완성 가이드 (0) | 2024.11.17 |