November 24, 2021

복잡한 상황에서 메서드를 호출하면 this 값을 잃어버리는 경우가 생깁니다.

예시를 살펴봅시다.

let user = {
  name: "John",
  hi() { alert(this.name); },
  bye() { alert("Bye"); }
};

user.hi(); // John (간단한 호출은 의도한 대로 잘 동작합니다.)

// name에 따라 user.hi나 user.bye가 호출되게 해봅시다.
*(user.name == "John" ? user.hi : user.bye)(); // TypeError: Cannot read property 'name' of undefined*

마지막 줄에서 조건부 연산자를 사용해 user.hi나 user.bye 중 하나가 호출되도록 했습니다. user의 name이 "John"이므로 user.hi가 호출될 것이라 예상하며 말이죠.

그런데 에러가 발생했습니다. 뒤에 ()가 있어서 메서드 hi가 즉시 호출될 것이라 예상했는데 원하는 대로 되지 않았네요.

에러는 메서드를 호출할 때 "this"에 undefined가 할당되었기 때문에 발생했습니다.

마지막 줄이 아래와 같았다면 에러 없이 잘 작동했을 겁니다.

user.hi();

그런데 아래 코드에선 에러가 발생하죠.

(user.name == "John" ? user.hi : user.bye)();

원인이 뭘까요? 원인을 알려면 obj.method()를 호출했을 때, 내부에서 어떤 일이 일어나는지 알아야 합니다.

요약

참조 타입은 자바스크립트 내부에서 사용되는 타입입니다.

.이나 대괄호를 사용해 객체 프로퍼티인 메서드(obj.method())에 접근하려 하면 정확한 프로퍼티 값이 반환되는 것이 아니라 특별한 형태의 값인 ‘참조 타입’ 값이 반한됩니다. 이 참조타입 값엔 프로퍼티 값과 프로퍼티가 정의된 객체 정보가 담겨있습니다.

()를 사용해 메서드를 호출할 때, 메서드 내에서 사용되는 this에 제대로 된 객체 정보를 전달해 줄 수 있는 이유가 바로 ‘참조 타입’ 덕분입니다.

그런데 .이나 대괄호 이외의 연산에선 참조 타입이 그냥 프로퍼티 값으로 변해버립니다. 객체 메서드라면 함숫값으로 변해버리죠.

이런 내부 동작은 보이지 않는 곳에서 일어납니다. 참조 타입이 어떻게 동작하는지 알아야 해결할 수 있는 문제는 표현식을 이용해 동적으로 객체에서 메서드를 가져올 때와 같이 자주 발생하지 않습니다.