[ JavaScript ] this 키워드에 대하여

DaiVernon·2021년 6월 4일
3

JavaScript

목록 보기
5/10
post-thumbnail

"This" Keyword


자바스크립트의 함수 바디에는 특별한 읽기 전용 값인 this가 존재합니다. this는 일반적으로 객체지향프로그래밍 개념과 매우 밀접한 연관이 있습니다. 자바스크립트에서는 this를 객체지향 프로그래밍뿐만 아니라 사용할 수 있는 다른 방법들이 존재합니다.

일반적으로 this는 객체의 프로퍼티로 존재하는 함수에서 의미가 있습니다. 메서드를 호출하면 this는 호출된 메서드를 소유한 객체와 묶이게 됩니다.

const obj = {
	name: 'James',
  	speak() { return `My name is ${this.name}!`; },
}

obj.speak()를 호출하면 this는 obj에 묶이게 됩니다.

obj.speak();     // "My name is James!"

다른 변수에 함수를 할당하면 this는 어떻게 되나요?


this는 함수를 어떤 방식으로 선언했느냐가 아니라 어떤 방식으로 호출했느냐에 따라 달라지게 된다는 것을 이해해야 합니다. 즉 speak 함수의 this가 obj에 묶인 이유는 speak가 obj의 프로퍼티로 존재하기 때문이 아닙니다. obj에서 speak가 호출됐기 때문입니다. 같은 함수를 다른 변수에 할당하여 선언하면 결과가 달라지게 됩니다.

const test = obj.speak;
test === obj.speak; // true 두 변수는 현재 같은 함수를 가리킵니다.
test();           // "My name is undefined!"

함수를 다른 변수에 할당해 호출하면 자바스크립트는 현재 이 함수가 어디에 속해있는지 알지 못합니다. 따라서 this는 undefined에 묶이게 됩니다.

중첩된 함수 안에서 this는 어떻게 되나요?


중첩된 함수에서 this를 사용하다 보면 지금 this가 어디에 묶여있는지 헷갈릴 때가 많습니다.

const obj = {
  name: "Julie",
  greetBackward: function () {
    function getReverseName() {
      let nameBackwards = "";
      for (let i = this.name.length - 1; i >= 0; i--) {
        nameBackwards += this.name[i];
      }
      return nameBackwards;
    }
    return `${getReverseName()} si eman ym ,olleH`;
  },
};

obj.greetBackward();

이 예제에서는 이름을 거꾸로 쓰고 싶어 중첩 함수 getReverseName을 사용했지만 getReverseName은 프로그래머가 의도한대로 동작되지 않습니다. obj.greetBackward()를 호출하는 시점에서는 this가 의도대로 obj에 묶이지만 greetBackward 안에서 중첩 함수 getReverseName을 호출하는 순간부터 this는 obj가 아닌 다른 곳에 묶이게 됩니다.

이런 문제를 해결하기 위해 가장 많이 사용되는 방법은 this를 다른 변수에 할당시켜 주는겁니다.

const obj = {
  name: "Julie",
  greetBackward: function () {
    const self = this;
    function getReverseName() {
      let nameBackwards = "";
      for (let i = self.name.length - 1; i >= 0; i--) {
        nameBackwards += self.name[i];
      }
      return nameBackwards;
    }
    return `${getReverseName()} si eman ym ,olleH`;
  },
};

obj.greetBackward();

이 방법은 ES5까지 널리 쓰이던 방법입니다. this를 self나 that에 할당해서 사용하는 방법입니다.

화살표 표기법으로 중첩함수 this 해결하기


화살표 함수에는 일반적인 함수 표기법과의 중요한 차이가 존재합니다. 바로 this가 화살표 함수 안에서는 언제나 상위스코프의 this에 묶이게 됩니다. 이를 정적으로(lexically)하게 묶인다고 표현하고 이를 lexical this 라 부릅니다.

이를 활용하여 위에서 작성한 greetBackwards 예제의 문제를 해결할 수 있습니다. 화살표 함수를 사용해서 내부 함수안에서 this를 사용할 수 있게 되기 때문입니다.

const obj = {
  name: "Julie",
  greetBackward: function () {
    const getReverseName = () => {
      let nameBackwards = "";
      for (let i = this.name.length - 1; i >= 0; i--) {
        nameBackwards += this.name[i];
      }
      return nameBackwards;
    };
    return `${getReverseName()} si eman ym ,olleH`;
  },
};

obj.greetBackward();

기타


이외에도 함수의 this가 어디에 묶여있는지 명확하게 알 수 없도록 호출했을 경우 this가 어디에 묶여있는지 결정하는 방법은 매우 복잡합니다. 스트릭트 모드인지, 아닌지, 함수를 어디에서 호출했는지등등 여러가지 요소에 의해 결정되므로 그런 상황들은 피하는 것이 최선입니다.

참고자료

profile
클린 코드, 클린 아키텍처

0개의 댓글