this 작동 범위
let audio = {
title: 'a',
title2 : this.title,
play() {
console.log('play this: ', this.title);
}
};
console.log(audio.title2); //undefined
audio.play(); // play this: a
위 코드에서 함수 블록 스코프 내에 선언되지 않은 this는 undefined가 되어 제대로 작동하지 않는다.
따라서 this는 반드시 함수 블록 스코프 내에서 선언되어야 올바르게 작동한다.
함수 호출 방식과 this 바인딩
메소드에서 this 사용
// Method => object
const audio = {
title: 'a',
play() {
console.log('play this', this);
}
}
audio.play();
// play this {title: 'a', play: ƒ}
// play: ƒ play()
// title: "a"
// [[Prototype]]: Object
메소드 내부의 this는 해당 메소드를 호출한 객체를 가리킨다.
var obj1 = {
name: 'Lee',
sayName: function() {
console.log(this.name);
}
}
var obj2 = {
name: 'Kim'
}
obj2.sayName = obj1.sayName;
obj1.sayName(); // Lee
obj2.sayName(); // Kim
obj2가 sayName 메소드를 obj1에서 가져왔으므로, sayName이 여전히 obj1에 바인딩된 상태에서 실행된다고 생각해서 obj2.sayName()의 결과가 Lee로 출력될 것이라고 착각할 수 있다.
하지만 자바스크립트에서 this는 함수가 선언될 때가 아니라, 함수가 호출될 때 결정된다. 즉, sayName 메소드를 호출한 객체가 obj2이기 때문에, this는 obj2를 참조하게 되어 Kim이 출력된다.
함수에서 this 사용
Function => Window Object
function playAudio() {
console.log(this); //window
}
playAudio();
// Window {window: Window, self: Window, document: document, name: '', location: Location, …}
기본적으로 this는 전역 객체(Global object)를 가리키는데, 함수 어디에서 선언되었든 상관없이 함수에서의 this는 전역 객체를 가리킨다.
const audio = {
title: 'audio',
categories: ['rock', 'pop', 'hiphop', 'jazz'],
displayCategories() {
this.categories.forEach(function (category) {
console.log(`title: ${this.title}, category: ${category}`);
});
}
}
audio.displayCategories();
조금 더 깊이 들어가보자.
this.categories.forEach(function (category) {
여기에서의 this는 displayCategories 메소드에서 사용되고 있다. 그럼 이 메소드를 호출한 객체는 audio이므로 문제없이 categories를 가리키게 된다.
console.log(`title: ${this.title}, category: ${category}`);
문제는 여기에서의 this이다. 이 this 또한 displayCategories 메소드에서 사용되고 있기 때문에 제대로 audio 객체의 title을 가리킨다고 생각할 수 있다.
하지만 코드를 잘보면 this.title은 메서드에 있는 게 아닌 보통 함수 안에 있는 것이기 때문에 audio 객체를 가리키는 게 아닌 window 객체를 가리키게 된다.
따라서 실행해보면 this.title이 undefined로 출력되는 것을 확인할 수 있다.
title: undefined, category: rock
title: undefined, category: pop
title: undefined, category: hiphop
title: undefined, category: jazz
하지만 우리는 audio의 title을 가져와야하는 상황이다. 그럼 어떻게 해야할까? 두 가지의 방법이 있다.
forEach의 두 번째 매개변수 : thisArg
const audio = {
title: "audio",
categories: ["rock", "pop", "hiphop", "jazz"],
displayCategories() {
this.categories.forEach(function (category) {
console.log(`title: ${this.title}, category: ${category}`);
}, this);
},
};
audio.displayCategories();
// title: audio, category: rock
// title: audio, category: pop
// title: audio, category: hiphop
// title: audio, category: jazz
forEach의 첫 번째 매개변수는 콜백 함수이고, 두 번째 매개변수인 thisArg는 콜백 함수 내에서 this로 참조할 객체를 지정하는 용도로 사용된다. 즉, thisArg에 전달된 객체를 콜백 함수 내에서 this로 사용할 수 있게 된다.
this.categories.forEach(function (category) {
console.log(`title: ${this.title}, category: ${category}`);
}, this);
따라서 두 번째 인자로 audio를 가리키는 this를 넘겨주어, 콜백 함수 내에서 this가 audio를 올바르게 참조하도록 한다.
화살표 함수 사용하기
const audio = {
title: 'audio',
categories: ['rock', 'pop', 'hiphop', 'jazz'],
displayCategories() {
this.categories.forEach((category) => {
console.log(this);
});
}
}
audio.displayCategories();
// {title: 'audio', categories: Array(4), displayCategories: ƒ}
화살표 함수 안에 있는 this는 항상 상위 스코프의 this를 가리킨다. 이것을 Lexical this라고 부르는데, 이 덕분에 콜백함수 내에서도 this가 audio를 참조하도록 할 수 있다.
생성자 함수에서 this 사용
// Constructor Function => {}
function Audio(title) {
this.title = title;
console.log(this);
}
const audio = new Audio('a');
// Audio
// title: "a"
생성자 함수에서의 this는 빈 객체를 가리킨다.
💡 Tip
자바스크립트의 생성자 함수
자바와 같은 객체지향 언어의 생성자 함수와 달리, 자바스크립트에서는 특별한 형식이 정해져 있지 않다. 단순히 기존 함수에 new 연산자를 붙여 호출하면 해당 함수가 생성자 함수로 동작하게 된다.
즉, 일반 함수도 new 연산자를 붙여 호출하면 생성자 함수처럼 동작할 수 있다. 이러한 혼동을 방지하기 위해, 생성자 함수의 이름은 보통 첫 글자를 대문자로 작성하는 것이 관례다.
'Language > JavaScript' 카테고리의 다른 글
[ JS ] Call & Bind & Apply 완벽 정리 (0) | 2024.10.10 |
---|---|
[ JS ] 자바스크립트 타입 총정리 (1) | 2024.10.09 |
[ JS ] var, let, const ( + 변수 호이스팅 ) (2) | 2024.09.19 |
[ JS ] 이벤트 흐름을 이해해보자 ( Event Bubbling & Capturing ) (0) | 2024.08.29 |