[JS] this는 도대체 뭘까? this의 개념과 예시 문제 풀이
자바스크립트 다양한 코드를 보다 보면 계속 this가 문득문득 등장하는데 정확한 개념을 이해하지 못해 답답했다. 계속 등장하는 김에 제대로 알고 가자! 어려운 개념인 만큼 잘 설명한 영상을 찾아봤다.
※ 본 포스팅은 아래 영상 내용을 토대로 공부하며 정리해 작성했습니다. 잘 모르겠다면 직접 영상을 보길 추천합니다.
✏️ this의 개념
대부분의 경우 this의 값은 ⭐️함수를 호출한 방법에 의해 결정된다.
실행중에는 할당으로 설정할 수 없고 함수를 호출할 때마다 다를 수 있다. ES5는 함수를 어떻게 호출했는지 상관하지 않고 this 값을 설정할 수 있는 bind 메서드를 도입했고, ES2015는 스스로의 this 바인딩을 제공하지 않는 화살표 함수를 추가했다.
+) 공부해보니 사투리로 이거 저거 뭐든 가리킬 때 하나로 부르는데 아는 사람들은 부르는 게 다 달라도 문맥에 따라 찰떡같이 알아듣는 것처럼, this도 비슷한 개념으로 대명사가 부를 때마다(함수를 호출) 문맥에 따라서(호출 방법에 따라서) 그 의미(값)가 달라진다. 또 예를 들어 거실에서 그거 달라고 할 때 항상 리모컨을 가리킨다고 하면(bind() 메서드로 값을 지정해 주면) 그거의 뜻은(this 값)은 거실에서 항상 동일할 수 있다.
값(Value)
실행 컨텍스트(global, function 또는 eval)의 프로퍼티는 비엄격 모드에서 항상 객체를 참조하며, 엄격 모드에서는 어떠한 값이든 될 수 있습니다.
전역 문맥
전역 실행 맥락에서 this는 엄격 모드 여부에 관계 없이 전역 객체를 참조한다.
// 웹 브라우저에서는 window 객체가 전역 객체
console.log(this === window); // true
a = 37;
console.log(window.a); // 37
this.b = "MDN";
console.log(window.b) // "MDN"
console.log(b) // "MDN"
+ (globalThis 프로퍼티를 사용하여 코드가 실행중인 현재 컨텍스트와 관계없이 항상 전역 객체를 얻을 수 있다.)
함수 문맥
함수 내부에서 this의 값은 함수를 호출한 방법에 의해 좌우된다.
✏️ 예시
const me = {
name: "Rachel",
getName: function () {
console.log("My Name", this);
},
};
me.getName(); // My Name {name: 'Rachel', getName: ƒ}
const globalMe = me.getName; // Window
globalMe();
const friends = {
name: "Monica",
getName: me.getName, // My Name {name: 'Monica', getName: ƒ}
};
friends.getName();
const btn = document.getElementById("button");
btn.addEventListener("click", me.getName); // button tag => this는 함수가 호출될 때 결정되는데 btn이 호출했으므로 button tag 자체가 this
// this 값을 고정시켜주기 위해 .bind 사용
const bindGetName = friends.getName.bind(me);
bindGetName(); // My Name {name: 'Rachel', getName: ƒ}
globalMe에서는 전역 문맥으로 웹 브라우저에서는 Window 객체가 전역 객체이므로 Window 객체를 반환한다.
위 다양한 함수 예시를 보면 함수를 호출하는 방법에 따라 this의 값이 달라지는 것을 알 수 있고 bind()로 값을 고정할 수도 있다.
▶ bind()
bind()메서드는 호출될 때 this키워드가 제공된 값으로 설정되고, 새 함수가 호출될 때는 제공된 인수 앞에 주어진 인수 시퀀스(sequence of arguments)가 있는 새 함수를 만듭니다.
// Syntax
bind(thisArg)
bind(thisArg, arg1)
bind(thisArg, arg1, arg2)
bind(thisArg, arg1, arg2, /* …, */ argN)
✏️ 문제 풀이
문제 - 1
const testCar = {
name: "benz",
getName: function () {
console.log("get Name", this); // benz
const innerFunc = function () {
console.log("innerFunc", this); // Window 객체가 호출했기 때문에 this는 Window
};
innerFunc();
},
};
testCar.getName();
이 코드에서 this의 값을 같게 하려면 어떻게 고쳐야 할까?
문제 - 1 해결 방법
// this 값 값게 해결 방법 1: 화살표 함수 사용
// 화살표 함수에서의 this는 함수가 속해있는 곳의 ⭐️상위 this를 계승받는다.
// 화살표 함수는 bind 메서드를 제공하지 않는다.
const testCar = {
name: "benz",
getName: function () {
console.log("get Name", this); // benz
const innerFunc = () => {
console.log("innerFunc", this); // benz
};
innerFunc();
},
};
testCar.getName();
화살표 함수 내에서는 this가 함수가 속해있는 곳의 상위 this를 계승받는다는 것을 기억하자!
문제 - 2
const ageTest = {
unit: "살",
ageList: [10, 20, 30],
getAgeList: function () {
const result = this.ageList.map(function (age) {
return age + this.unit; // [NaN, NaN, NaN]
});
console.log(result);
},
};
ageTest.getAgeList();
[10살, 20살, 30살] 이렇게 출력하고 싶은데 [NaN, NaN, NaN]이 찍힌다. 어떻게 고쳐야 할까?
문제 - 2 해결 방법
// 문제 -2 ⭐️ 해결 방법 1: 화살표 함수 사용
const ageTest = {
unit: "살",
ageList: [10, 20, 30],
getAgeList: function () {
const result = this.ageList.map((age) => {
return age + this.unit; // ['10살', '20살', '30살']
});
console.log(result);
},
};
ageTest.getAgeList();
문제 - 1과 동일하게 화살표 함수로 바꿔주면 함수 내부에서 this의 값을 계승받아 잘 출력할 수 있다.
// 문제 -2 해결 방안2
const ageTest = {
unit: "살",
ageList: [10, 20, 30],
getAgeList: function () {
const result = this.ageList.map(function (age) {
return age + this.unit; // ['10살', '20살', '30살']
}, ageTest);
console.log(result);
},
};
// 문제 -2 해결 방안3
const ageTest = {
unit: "살",
ageList: [10, 20, 30],
getAgeList: function () {
const result = this.ageList.map(function (age) {
return age + ageTest.unit; // ['10살', '20살', '30살']
});
console.log(result);
},
};
ageTest.getAgeList();
이런 식으로 해당 함수를 직접 지정해 주어도 올바르게 출력할 수 있다.
📌 정리
this를 쓰면 값이 계속 바뀔 수 있는데 this를 쓰려면 어떤 식으로 값을 지정해 주는 것이 좋을까?
1. 일반적으로 this를 쓰고 싶다면 일반 함수를 쓰자 => .bind()로 원하는 객체를 지정해 줄 수 있다. (좀 더 예측 가능)
2. 함수 내에 있는 함수는 상위의 값을 그대로 받는 경우가 많기 때문에 화살표 함수도 괜찮다.
대부분의 경우 this의 값은 함수를 호출한 방법에 의해 결정된다는 사실을 기억하자.
🙂 공부하면서 정리한 글입니다. 피드백과 공감 환영합니다.