자바스크립트 다양한 코드를 보다 보면 계속 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의 값은 함수를 호출한 방법에 의해 결정된다는 사실을 기억하자.
🙂 공부하면서 정리한 글입니다. 피드백과 공감 환영합니다.
'프로그래밍 > JavaScript' 카테고리의 다른 글
[Js] Array에서 순서 변경하지 않고 특정 값 삭제하기 🧚🏻♀️ / 제일 작은 수 제거하기 (0) | 2023.01.21 |
---|---|
[Js] 구조 분해 할당(Destructuring assignment)이란? (1) | 2023.01.18 |
[Js] Array push와 concat의 차이 (0) | 2023.01.09 |
[JS] 어떤 Number가 제곱수인지 어떻게 알까? / [프로그래머스] 제곱수 판별하기 (0) | 2023.01.07 |
[JS] Array 요소 추가, 제거, 길이 변경 메서드 정리 💛 (0) | 2023.01.05 |