this 탄생 배경
- 우리가 사는 실제세계에는 어떤 실체를 인식하기 위해, 그 실체의 특징이나 성질을 이용해 실체를 인식하고 구분한다.
- 이러한 개념을 프로그래밍에 접목하여
객체 지향 프로그래밍
이라는 패러다임이 만들어졌다.
- 이 때, 하나의 객체는 그 객체의 성질을 나타내는
상태 (property)
라는 개념과 그 상태를 조작하는 동작 (method)
이라는 개념(자료구조)으로 이루어진다.
- 하지만
method
가 객체의 상태를 변경하려면 먼저 자신이 속한 객체에 접근해야 한다.
- 자신이 속한 객체에 접근하는 방법은 객체를 가리키는
식별자(메모리 주소)
를 이용한 참조가 필요하다.
문제 발생
- 생성자 함수에서
method
를 정의 할 때, 자신이 생성할 인스턴스
를 가리키는 식별자에 접근할 수 없다.
- 그러나, 생성자 함수로
인스턴스
를 만들기 위해선 생성자 함수가 존재해야 한다
- 마치
deadlock
같은 상황이 생겼다.
- 따라서, 생성자 함수가 생성할
인스턴스
를 가리키는 특수한 식별자
필요
- 바로
this
이다.
this 란
- 자신이 생성할 인스턴스를 가리키는 자기 참조 변수
- 이를 통해 생성할 인스턴스의 프로퍼티와 메서드에 접근가능
- 자바스크립트 엔진에 의해, 코드 어디서든 암묵적으로 생성
- 함수 호출 시,
arguments
객체와 this
암묵적으로 함수 내부에 전달됨
- 즉,
this
는 함수 호출 방식에 의해 동적으로 결정됨 (생성될 인스턴스를 가리키므로)
📌 바인딩
- 식별자와 값을 연결 -> 식별자와 확보된 메모리 공간의 주소와 연결
- 객체의 메서드 내부 or 생성자 함수 내부에서만 의미가 있다. (일반 함수는 window 가리킴)
함수 호출 방식과 this 바인딩
일반 함수 호출
- 전역객체에 바인딩 ->
window
- 함수가 어디서 선언되건간에, 일반 함수로 호출되면 -> 전역객체 바인딩
- 콜백함수가 일반함수로 호출되도 마찬가지
- 예외:
- this를 변수에 할당
- 명시적 바인딩 (
.bind
)
- 화살표 함수 (화살표 함수 내부의 this는 상위 스코프의 this 가리킴)
메서드 호출
- 메서드을 호출할 때에는
객체.메서드
로 호출된다.
- 이때, 메서드 내부의
this
는 메서드를 호출한 객체
에 바인딩 된다. (소유한 X)
- 왜냐하면, 객체의 메서드는 프로퍼티에 바인딩된 함수이다. (프로퍼티 식별자자 메서드가 담겨있는 메모리 주소 가리킴)
- 이 말은 프로퍼티가 가리키는 함수 객체는 원래 객체에 포함되어 있지 않다.
- 따라서, 메서드가 어디에 위치해 있건, 메서드 안의 this는 호출한 객체을 가리킨다. (메서드는 일반 함수이고, 메서드 안의 this는 함수의 프로퍼티, 그리고 this는 호출시 동적으로 값이 정해지므로, 호출한 객체를 바인딩)
생성자 함수 호출
- 생성된 인스턴스를 가리킴
- 일반 함수로 호출시 this는 전역객체 가리킴
Function.prototype.apply/call/bind 메서드에 의한 간접 호출
apply
,call
은 본질적으로 함수를 호출하는 것이다. (함수의 arguments를 전달하는데 차이만 있음)
- 다만 함수를 호출함과 동시에, 호출한 함수의 this 프로퍼티를 선택한 특정 객체와 바인딩 시킨다.
apply
- f.apply(obj, [arg1, arg2, ...])
call
- f.call(obj, arg1, arg2, ...)
bind
- apply, call 처럼 함수를 호출하지 않고, 바인딩할 객체만 전달한다.
- f.bind(obj)()
- 메서드의 this 와 메서드 내부의 중첩함수나 콜백함수 안의 this가 일치하지 않을 때 사용 -> 화살표 함수 쓰면 해결 될 듯?