참조타입

참조 타입

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

1
2
3
4
5
6
7
8
9
let user {
name: 'John',
hi() {alert(this.name)},
bye() { alert('Bye') }
}

user.hi();; //John

(user.name == 'John' ? user.hi : user.bye)() // TypeError

에러는 메서드를 호출할 때 thisundefined 가 할당되었기 때문에 발생했다.

왜 이런 현상이 일어날까?

(user.hi)()는 정상 작동한다. 이는 (expression)() 형태에서는 참조 값이 아닌 함수 값 자체가 전달되기 때문이다.

참조 타입 자세히 알아보기

obj.method() 엔 연사이 두개 있다.

  1. . 은 객체 프로퍼티 obj.method에 접근한다.
  2. 괄호 ()는 점근한 프로퍼티를 실행한다.

첫번째 연산에서 얻은 this가 어떻게 두번째 연산으로 전달 될까?

1
2
3
4
5
6
7
8
9
10
let user = {
nsme: "John",
hi() {
alert(this.name);
},
};

// 메서드 접근과 호출을 별도의 줄에서
let hi = user.hi;
hi(); // this 가 undefined이기 때문에 에러가 발생한다.

자바스크립트에서 user.hi()를 의도한대로 동작 시키기 위해서 .은 함수를 반환 시키는 것이 아니라 참조 타입을 반환하게 된다.
참조 타입에 속하는 값은 (base, name, strict) 이 조합된 형태이다.

  • base: 객체
  • name: 프로퍼티 이름
  • strict: 엄격 모드에서 true

user.hi()로 프로퍼티에 접근하면 함수가 아닌, 참조형(참조 타입) 값을 반환한다. 엄격 모드에선 아래와 같이 반환된다.

1
2
// 참조형 값
user, "hi", true;

참조형 값에 ()를 붙여 호출하면 객체, 객체의 메서드와 연관된 모든 정보를 얻는다. 이 정보를 기반으로 this(=user) 가 결정된다.

참조 타입은 . 연산에서 알아낸 정보를 괄호 ()로 전달해 주는 중개인 역할을 한다.

()없이 user.hi를 호출하면 점연산이 아닌 연산이 된다(할당 연산). 이때는 참조 값이 아니라 함수 만 받아서 전달하기 때문에 this정보가 사라진다. obj.method()같이 점을 사용하거나, obj[method]() 같이 대괄호를 사용해 함수를 호출했을 때만 this 값이 의도한대로 전달된다. func.bind() 등을 이용하면 해결 하는 방법도 있긴 한다.