우당탕탕 개발일기
모던 자바스크립트 22. this 본문
면접 대비 질문 리스트를 뽑을 때마다 꼬옥 나오는 this.. 봐도봐도 모르겠던 this를 이번 기회에 아주 조져보겠다.
01. this란
const circle = {
radius: 5,
getDiameter() {
return 2 * circle.radius;
}
};
console.log(circle.getDiameter()); // 10 (ⓐ)
getDiameter 메소드 내에서는 메소드 자신이 속해있는 객체 circle을 참조하고 있다.
getDiameter 메소드가 호출되는 시점(ⓐ)에는 이미 객체 리터럴의 평가가 완료되어 객체가 생성되었고 circle이라는 식별자에 생성된 객체가 할당된 이후이다. 따라서 getDiameter 메소드 내부에서 circle 식별자를 참조할 수는 있다.
하지만, 자기 자신이 속한 객체를 재귀적으로 참조하는 방식은 일반적이지도 않을 뿐더러, 바람직한 방법도 아니다.
만약 객체 리터럴이 아닌 생성자 함수 방식으로 인스턴스를 생성하는 경우라면?
function Circle(radius) {
????.radius = radius; // (ⓑ)
}
Circle.prototype.getDiameter = function() {
return 2 * ????.radius; // (ⓒ)
};
const circle = new Circle(5); // (ⓓ)
생성자 함수가 존재해야 생성자 함수로 인스턴스를 생성 가능한데(ⓓ),
생성자 함수를 '정의'하는 시점에는 아직 인스턴스를 생성하기 이전이므로(ⓑ, ⓒ)생성자 함수가 생성할 인스턴스를 가리키는 식별자를 알 수 없다.
이럴 때 자신이 속한 객체 혹은 자신이 생성할 인스턴스가 필요한데 이를 위해 자바스크립트가 제공하는 것이 바로 this이다.
자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수인 this를 통해
자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메소드를 참조할 수 있다.
this를 이용해 위의 예제들을 아래와 같이 수정할 수 있다.
const circle = {
radius: 5,
getDiameter() {
// this는 메소드를 호출한 객체를 가리킨다.(circle)
return 2 * this.radius;
}
};
console.log(circle.getDiameter()); // 10
function Circle(radius) {
// this는 생성자 함수가 생성'할' 인스턴스를 가리킨다.
this.radius = radius;
}
Circle.prototype.getDiameter = function() {
// this는 생성자 함수가 생성'할' 인스턴스를 가리킨다.
return 2 * this.radius;
};
// 인스턴스 생성
const circle = new Circle(5);
console.log(circle.getDiameter()); // 10
자바나 C++과 같이 클래스 기반 언어에서는 this가 항상 클래스가 생성하는 인스턴스를 가리키는 반면,
자바스크립트의 this는 함수가 호출되는 방식에 따라 this 바인딩, 즉 this가 가르키는 값이 동적으로 결정된다.
바인딩이란? 식별자와 값을 연결하는 과정.
예를 들어 변수 선언은 식별자 변수 이름과 확보된 메모리 공간의 주소를 바인딩 하는 것이고,
this 바인딩은 식별자 this와 this가 가르킬 객체를 바인딩하는 것이다.
this는 어디서든 참조가 가능하다. 함수 내부 뿐만 아니라, 전역에서도 참조 가능하다.
만약 전역에서 참조할 경우 이 때 this는 전역 객체인 window를 가리킨다. 일반 함수 내부에서도 마찬가지로 window를 가리킨다.
02. 함수 호출 방식에 따른 this 바인딩
this 바인딩은 함수 호출 방식, 즉 함수가 어떻게 호출되었는지에 따라 동적으로 결정된다.
다만 주의할 점은 같은 함수도 다양한 방식으로 호출할 수 있다는 것이다.
1) 일반 함수 호출
전역 함수, 중첩 함수 상관없이 일반 함수로 호출하는 경우 this에는 전역 객체 window가 바인딩된다.
다만 this의 역할은 객체의 프로퍼티나 메소드를 참조하기 위한 자기 참조 변수이므로 객체를 생성하지 않는 일반 함수에서는 의미가 없다.
그래서 strict mode가 적용되었다면 일반 함수 내부에서 this에는 undefined가 바인딩된다.
2) 메소드 호출
메소드 내부의 this는 프로퍼티로 메소드를 가지고 있는 객체와는 관계 없고 메소드를 호출한 객체에 바인딩된다.
3) 생성자 함수 호출
생성자 함수 내부의 this에는 생성자 함수가 미래에 생성'할' 인스턴스가 바인딩된다.
4) Function.prototype.apply/call/bind 메소드에 의한 간접 호출
Function.prototype의 메소드인 apply/call/bind 메소드는 모든 '함수'가 상속받아 사용할 수 있다.
(1) Function.prototype.apply, Function.prototype.call
apply와 call 메소드는 this로 사용할 객체와 인수 리스트를 인수로 전달받아 함수를 '호출'한다.
함수를 호출할 때 첫번째 인수로 전달 받은 객체를 호출한 함수의 this에 바인딩한다.
getThisBinding이라는 함수에 thisArg 인수를 전달하는 것이 아니라, getThisBinding함수의 this에 바인딩하는것이다.
함수의 인수를 전달하고 싶다면, apply, call의 두 번째 인수로 전달하면 된다.
이 때 apply는 배열로 묶어서, call은 쉼표로 구분한 리스트 형식으로 전달한다는 차이점이 있다.
(1) Function.prototype.bind
bind는 apply, call과 다르게 함수를 호출하는 것이 아니다.
다만 첫 번째 인수로 전달한 값으로 this 바인딩이 교체된 함수를 새롭게 생성해 반환한다.
bind 메소드는 메소드의 this와 메소드 내부 중첩 함수 혹은 콜백 함수의 this가 불일치하는 문제를 해결할 때 유용하게 사용된다.
'What I Learned > JavsScript' 카테고리의 다른 글
모던 자바스크립트 26. ES6 함수의 추가 기능 (1) | 2024.06.17 |
---|---|
모던 자바스크립트 24. 클로저 (0) | 2024.06.05 |
모던 자바스크립트 19. 프로토타입 (0) | 2024.05.13 |
모던 자바스크립트 16. 프로퍼티 어트리뷰트 (0) | 2024.05.02 |
모던 자바스크립트 14. 전역 변수의 문제점 (0) | 2024.04.30 |