[React/JS] this 이해하기 (+ class component)

Kimyujin·2021년 8월 19일
1

오늘은 위코드 프리온보딩 수업시간에 들었던 내용과, 내가 알고있는 부분들을 합해서 정리해보려한다.
그냥 개념적으로 알고있던 this가 예리멘토님이 너무 와닿게 설명해주셔서 이제야 조금씩 이해가 된다.

this란

1. 정의

this는 this가 바라보고 있는 객체이며, 어디서 호출되느냐에 따라 달라진다.
tihs는 자신이 속한 객체 or 자신이 생성할 인스턴스를 가리키는 자기 참조 변수(Self-referencing variable)이다.

2. this 맛보기

처음 자바스크립트 공부를 할 때 this는 그렇게 어렵지않다. this를 개념적으로 접근하기 시작할 때 어려워진다.

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  getName() {
      return this.name;
  }
};

this를 이용해서 클래스를 정의하면, 다음부터 새로 만들어지는 객체는 자기 자신을 이용한다.

const jelly = new Person('Kim', 13);
const brown = new Person('Park', 20);

jelly.getName(); // Kim
brown.getName(); // Park

Person 클래스는 this를 이용해서 자기자신을 정의한다.
jelly와 brown은 Person 클래스를 이용해서, 독립된 객체로 만들어졌다.
이것은 this는 자신이 생성할 인스턴스를 가리킨다 라고 앞에서 말한 의미와 같다.

3. 암시적 binding 😄

앞에서 본 것처럼 this는 알아서 결정된다. 자바스크립트 엔진이 this를 정한다. 이것을 암시적 바인딩이라고 칭한다.
(node에서와 브라우저에서 this는 약간 다른데, 나는 프론트엔드 공부하는 사람이기 때문에 브라우저에서만 볼 것이다.)

3-1. 일반 함수에서의 this

전역에서의 this에는 전역 객체(window)가 바인딩된다.
일반 함수에서도 this에는 전역 객체(window)가 바인딩된다.

console.log(this === window); // true

function check() {
	console.log(this);
};
check(); // window

3-2. 메서드에서의 this

메서드 내부의 this에는 메서드를 호출한 객체가 바인딩된다.

const myDog = {
  weight: "5kg",
  getWeight() {
    return `${this.weight} 입니다.`;
  },
};

myDog.getWeight(); //5kg 입니다.

// this에는 myDog이 바인딩 된다.

3-3. 생성자 함수에서의 this

생성자 함수 내부의 this에는 생성할 인스턴스가 바인딩된다.

function Person(name, age) {
  this.name = name;
  this.age = age;
}

이렇게 간단하게 사용할 경우에는 this에 대해 고민할 필요가 별로없다. 하지만 함수들이 중첩이 된다 싶을 때부터 this는 예상한 것과 다른 것을 가리킨다.

4. this가 예상한 값이 아닐때 😟

아까 (3-1)일반 함수에서, 일반 함수에서는 this에 전역 객체가 바인딩 된다고 했다.
그런데 우리가 흔히 쓰는 중첩 함수, 콜백 함수도 생김새는 일반 함수와 같다.
즉, 중첩 함수와 콜백 함수에서 this에는 무조건 전역 객체(window)가 바인딩된다.


this 바인딩하기

1. this 바인딩은 어디서 쓰일까?

this는 자바스크립트 엔진에 의해 알아서 정해진다.
명시적으로 this를 바인딩할 수 있다는 것을 알아야하는 이유는, 앞에서 본 것처럼 this라는 것이 개발자가 원하는 그 객체가 아닐 수도 있기 때문이다. 에러를 찾고, 활용하기 위해 알아야한다.
또 이 바인딩을 알아둬야 오픈소스도 이해하고 사용할 수 있다.
1) React 클래스 컴포넌트에서도 this바인딩을 이용한다.
2) 개인적으로 찾아본 오픈소스중 함수형 컴포넌트였지만 this바인딩을 활용한 오픈소스를 본 적이 있다.

2. 바인딩 방법

2-1. Function.prototype.call

this를 바인딩할 수 있게 print함수와 update함수를 만들어서 적용해보자.

function print() {
  return `hi, ${this.name}`;
}

function update(age, hobby) {
  this.age = age;
  this.hobby = hobby;
}
// 이 함수들을 새로운 객체에게 사용할 수 있다.

1) 이름 출력하기

const person = {
  name: "yujin"
};

console.log(print.call(person)); // hi, yujin
// print함수를 부른다. this는 person으로 바인딩한다.

2) person객체 업데이트하기

update.call(person, "11", "코딩"); 
// update함수를 부른다. this는 person으로 바인딩하며 update인자에 ("11,"코딩")을 적용한다.
console.log(person); // {name: "yujin", age: "11", hobby: "코딩"}

코드 보러가기(code sandbox) 👈

2-2. Function.prototype.apply

apply는 call과 거의 같다. 인자를 나열 형식이 아닌, 배열로 받는다는 차이가 있다.

update.apply(person, ["11", "코딩"]);
console.log(person); // {name: "yujin", age: "11", hobby: "코딩"}

2-3. Function.prototype.bind

call과 apply는 호출 자체가 목표이다. bind는 호출하지 않고, this만 바인딩한다.
만약 아래에 bind대신 call이나 apply가 있었다면 결과는 'hi yujin' 이었을 것이다. 하지만 bind를 썻기때문에 함수의 정보가 출력됐다.

bind와 call/apply의 차이점을 좀 더 보자.

(1) bind
update함수에 bind로 this를 person으로 bind해버리고, getOld라는 이름에 담는다.
getOld는 인수를 받을 수 있는 함수가 되어버린다.

(2) call
update함수에 call로 this를 person으로 bind해서 변수에 담아도, 아무것도 담기지 않는다. call은 호출하는 메서드이기 때문이다.

클래스 컴포넌트를 보면 좀 더 이해하기 쉽다.

this바인딩을 해주지 않는다면, this는 호출될 때 결정되므로, this는 HomeContainer가 아닌 button요소가 될 것이다.

2-4. 화살표 함수, 클래스 필드

함수를 선언할 때, 우리는 이런식으로 이용한다.
1) 함수 선언문

function add(x, y) {
	return x + y;
};

2) 화살표 함수

const add = () => {
	return x + y;
};

화살표 함수로 작성할 경우에는, this가 상위 스코프의 this를 그대로 참조한다.
React class component에서는클래스 필드에 화살표 함수를 정의하면, this가 상위 스코프인 constructor 내부의 this로 바인딩된다.


this 관련 용어 정리

이름설명
this자신이 속한 객체 혹은 자신이 생성할 인스턴스를 가리키는 변수
this 바인딩this가 정해지는 현상
call, applythis를 원하는 것으로 바인딩하면서 호출하는 메서드
bindthis를 원하는 것으로 바인딩하는 메서드
일반 함수일반적인 함수. 중첩함수 혹은 콜백함수도 일반 함수이며, 일반 함수의 this는 전역 객체(window)
화살표 함수this가 상위 스코프로 자동 바인드되는 함수 선언 방식
클래스 필드클래스 내부에서 변수처럼 사용되는 것 (private)

Reference

mdn, "this", https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this
이브라히모비치, "call, apply, bind 차이 - this의 사용", https://ibrahimovic.tistory.com/29
이응모, [모던 자바스크립트 Deep Dive], this, 342p
이재승, [실전 리액트 프로그래밍], 클래스형 컴포넌트 기본 사용법, 222p

0개의 댓글