이 글은 전적으로 아래 영상을 따릅니다.
https://youtu.be/7RiMu2DQrb4?si=h744LMvNaWwIUTs6
This 바인딩
일반적으로 객체 지향 언어에서 this 라는 예약어는 함수가 속해 있는 객체 자기 자신과 관련이 깊습니다.
하지만 일급 객체인 자바스크립트 함수는
const foo = function foo2(){}
1. 변수나 데이터에 할당 할 수 있고
function foo1(foo2){}
2. 다른함수의 인수
function foo1() {
...
return foo1
}
3. 반환값으로 사용할 수가 있습니다.
이러한 특징으로 인해 자바스크립트 함수는 다양한 환경에서 호출 될 수 있습니다.
단독호출
특정 객체의 매서드로써 호출
동일한 함수가 서로 다른 객체에 의해서 호출
이렇듯 함수가 선언된 이후에 어떤 환경에서 어떤 객체에 의해 호출될지 예측하기 어렵습니다.
서로 다른 사람이 내 연락처 앱을 이야기 하지만 완전히 다른 전화번호부를 가지고 있듯이
누가 내 라고 할때마다 표현의 의미가 완전히 달라집니다.
=> 완벽하게 같은 함수라도 어떤 환경, 메서드에 호출되느냐에 따라 this도 달라집니다.
자바스크립트에서 모든 함수는 this를 가지고 있습니다.
함수가 호출되면 그때 그때 상황에 따라 this가 가르키는 객체가 결정됩니다.
함수가 호출될 때마다 this가 동적으로 결정되는 것을 this가 그 객체에 바인딩된다 라고 표현합니다.
자바스크립트 엔진은
프로그램을 실행하면 모든 실행 가능한 코드를 평가해서 실행 문맥 (실행 컨텍스트)를 만듭니다.
이 때 실행 문맥에 this에 대한 정보가 담기게됩니다.
프로그램이 실행이 되면 전역 코드 평가 -> 전역 실행 문맥 만듭니다.
함수가 실행이 되면 전역 코드 실행을 잠깐 멈추고 또 다시 실행 문맥을 만듭니다.
함수가 실행이 되는 바로 이 타이밍에서 this 바인딩 컴포넌트의 값이 결정됩니다.
Object.Function()
일반적으로 this는 점 앞에 있는 객체
즉, 호출 당시 함수를 포함하고 있는 객체에 바인딩됩니다.
만약에 함수가 객체에 의해 호출되지 않는 상황에서는 어떻게 바인딩 될까요?
함수가 호출되는 상황에 따라 다릅니다.
기본/ 암시/ new / 명시 바인딩이 있고 우선순위가 존재합니다.
1. 기본 바인딩
함수를 단독 실행 시키면 전역 객체에 바인딩 됩니다.
브라우저 실행환경에서는
비 엄격모드 : 전역 객체인 윈도우 객체에 바인딩 되고
엄격보드 : undefined
- 전역 객체가 바인딩 대상에서 아예 제외됩니다.
- this가 바인딩될 객체가 존재하지 않기 때문에 undefined 값을 가짐
노드환경에서는
전역 객체는 글로벌이므로 글로벌 객체에 바인딩
상황에 따라 다르게 바인딩
함수 코드 안에서가 아니라 전역 코드 안에서 this 출력하면 빈 객체
모듈 객체에 있는 exports객체이다.
두가지 방향으로 바인딩 된다.
2. 메소드 호출(암시적 바인딩)
점 바로 앞에 있는 객체에 바인딩
암시적 바인딩에서 조심해야할 점!
자바스크립트에서 객체를 할당한 변수는 해당 객체에 대한 참조값을 저장합니다.
obj.getName 과 callback이 완벽하게 동일한 함수를 참조하고 있고
동일한 방식으로 괄호를 붙여서 함수를 호출하고 있는데
한번이라도 복제가 일어나고 다른 변수를 거치면 바인딩이 안됩니다.
왜?!!!!
점 연산...
점연산(obj.function())이나 대괄호 연산을 통해 객체의 프로퍼티에 우리가 접근을 하면
참조 타입이라고 하는 특별한 값을 반환해 줍니다.
참조 타입은 프로퍼티뿐만 아니라
프로퍼티를 가지고 있는 객체와 strict모드인지 아닌지에 대한 여부를 같이 가지고 있는 하나의 타입입니다.
예를 들어서 엄격 모드에서 obj.getName에 접근을 하면
obj.getName : (obj, getName, true)
base: 객체
name: 메서드 이름
strict : 엄격모드 true
이러한 참조 타입에 바로 괄호를 붙여서 함수를 호출하게 되면
그 함수안에 있는 this가 참조타입에 있는 객체를 찾아서 바인딩을 하게 됩니다.
이게 바로 암시적 바인딩입니다.
obj.getName(); //참조 타입을 통해 암시적 바인딩
function showReturnValue(callback){ //함수의 참조값만 전달
callback(); // 함수 단독 실행
}
점연산, 대괄호 연산을 제외한 다른 연산들은 참조 타입이 아니라 해당 프로퍼티의 값만 전달
아무리 점 연산을 통해 참조타입을 얻어내도 다른 변수에 할당하는 순간 프로퍼티의 값 또는 참조하고 있는 참조값만 남는다.
따라서 점 연산을 통해 얻은 값은 바로 함수로 호출 하지 않고서는 암시적 바인딩을 기대할 수 없다.
인수로 전달된 콜백의 참조도 객체에 대한 어떠한 정보도 포함을 하지 않기 때문에 함수로 단독 호출한것과 같이 동작.
3. 명시적 바인딩
바인딩된 this 안잃어버리는 해결방법
call, apply, bind 명시적으로 바인딩할 수 있는 메서드들
call, apply : this를 바인딩할 객체를 지정한 상태로 함수를 호출 할 수 있습니다.
첫번째 인자로 this를 바인딩 할 객체를 전달, 나머지 인수
call은 인수를 하나하나전달
apply는 배열이나 유사배열형태로 전달
bind는 this가 참조하는 객체를 고정시켜줍니다.
첫번째 인자로 this를 바인딩할 객체, 이후엔 인수로 사용될 값
반환하는 특수한 객체가 있습니다.
그 객체는 마치 항상 this가 특정 객체에 바인딩 되어있는 함수 처럼 행동합니다.
이렇게 항상 같은 객체에 바인딩 되도록 강제 하는 방법 - > 하드 바인딩
4. new 바인딩
자바스크립트 함수를 new 연산자와 함께 호출하게 되면 생성자 함수로써의 역할을 함수가 수행할 수 있게 됩니다.
1. new 연산자 호출을 하면 새로운 객체를 생성
2. 함수의 코드를 실행을 하고
3. 생성한 객체를 반환해줍니다.
그리고 이 과정에서 this는 새로 생성한 객체에 바인딩 됩니다.
이런 과정을 통해 프로퍼티가 정해진 객체를 반환하는 생성자 역할을 수행할 수 있게 됩니다.
이렇게 new 연산자로 함수를 호출할 때 this가 바인딩 되는 규칙을 new binding이라고 합니다.
우선순위에 따라 바인딩됩니다.
new > 암시적 > 명시적 > 기본
코딩하다 보면 중복호출 될 수 있으므로 우선순위를 가집니다.
어떤것에도 해당되지 않으면 전역객체나 undefined 값을 가지게 됩니다.
화살표함수(ES6)와 this
다른 함수들이랑 this가 바인딩 되는게 다름
const obj = {
name: "summer",
showNameInSec(sec) {
setTimeout(() => {
console.log(this.name);
}, sec);
},
};
obj.showNameInSec(1000);
showNameInSec함수 안에서 setTimeout함수를 호출하고있고
setTimeout함수에 콜백으로 화살표 함수를 전달하고 있는 상황
일반함수라면 undefined임 하지만 정상적 출력함.
왜.....?
화살표함수는 상위 실행 문맥 유지
렉시컬 스코프와 관계없이
호출 당시에 의존하는 기존의 바인딩 규칙은
화살표 함수 안에서 this에게 전혀 의미가 없습니다.
화살표 함수 안에서 this는
선언될 당시에 상위 스코프에 해당하는 실행 문맥상에 this 바인딩 컴포넌트를 참조합니다.
쉽게 말해서 상위스코프의 this를 참조합니다.
따라서 this는 showNameInSec 함수 실행 문맥에 있는 this와 같은것입니다.
상위 스코프를 참조하는 모습과 비슷하며
이런 특징을 같는 this를 어휘적 this 라고 부릅니다.
'JavaScript' 카테고리의 다른 글
[Javascript]이벤트루프 (0) | 2023.09.14 |
---|---|
실행컨텍스트 (Execution Context) (0) | 2023.09.04 |
모듈(Module) (0) | 2023.09.01 |
클로저 (Closure) (0) | 2023.08.30 |
스코프(scope) (2) | 2023.08.28 |