함수 정의 방식별 `this`, 그리고 `bind()`

저뉼(스님?)·2023년 3월 7일
0

나만의 설명

목록 보기
2/11

(2024-02-17 보완)

this

JavaScript에서 함수를 정의하는 두 가지 방법

  • 화살표를 사용하는 방법
  • function 키워드를 사용하는 방법

이 두 가지 방법은 this에서 차이가 있다.

object의 메서드를 두 가지 방법으로 구현해 보겠다.

const objectA = {
    logThis: () => console.log(this) // 화살표 사용 방법
}

const objectB = {
    logThis: function() { // `function` 키워드 사용 방법
        console.log(this);
    }
}

objectA.logThis(); // Window {0: global, window: Window, self: Window, document: document, name: '', location: Location, …}
objectB.logThis(); // {logThis: ƒ}

function 키워드를 사용한 logThis()는 자체적으로 this를 바인딩한 반면,
화살표를 사용한 logThis()objectAthis를 그대로 이어받았다. 다시 말해, 부모 스코프(또는 lexical scope)의 this를 이어받은 것.
(참고로, 브라우저 콘솔의 경우 최상위 스코프의 thiswindow)

덧붙이면,
counter.increment()과 같은 식으로 호출될 때,
. 오른쪽의 함수 increment()function 키워드를 사용한 함수라면,
increment() 함수 안에서의 this. 왼쪽에 있는 counter가 되는 것.

따라서, 아래처럼 this를 사용해야 하는 경우에는 function 키워드를 사용해야 한다.

const counter = {
  count: 0,
  increment() { // `function` 키워드 사용 방법에서 키워드를 생략한 축약 표현
    this.count += 1;
  }
}

console.log(counter.count); // 0
counter.increment();
counter.increment();
console.log(counter.count); // 2

의도대로 increment()countercount를 잘 증가시킨다.

그런데 이때, counterincrement()만 필요해서 따로 변수에 할당하면 어떻게 될까?

const incrementCount = counter.increment;

console.log(counter.count); // 0
incrementCount();
incrementCount();
console.log(counter.count); // 0

의도대로 동작하지 않는다. this가 달라졌기 때문이다. (함수에서 로그를 찍어 보면 확인 가능)
increment() 함수의 thiscounter(에 할당한 object)지만,
incrementCount() 함수의 thisWindow가 되었다.

참고로, 실무에서 나는 코드를 좀 더 안전하게 짜겠다고 PrismaClient의 일부 메서드만 리포지토리의 프로퍼티로 복사하다가 이런 문제를 겪음.

bind()

그럼 this를 유지하려면 어떻게 해야 할까?
아래처럼 .bind()를 사용하면 된다.

const incrementCount = counter.increment.bind(counter);

0개의 댓글