HTML&CSS&Javascript/JS

[JS Deep Dive] 22장 this

킹우현 2023. 11. 24. 20:35

1.this 키워드

객체는 상태(state)를 나타내는 프로퍼티와 동작(behavior)를 나타내는 메서드를 하나의 논리적인 단위로 묶은 복합적인 자료구조다.

 

동작을 나타내는 메서드는 자신이 속한 객체의 상태, 즉 프로퍼티나 메소드를 참조하고 변경할 수 있어야 한다. 이때 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야 하는데, 이때 this를 사용한다.

 

function Circle(radius) {
  // 이 시점에는 생성자 함수 자신이 생성할 인스턴스를 가리키는 식별자를 알 수 없다.
  ????.radius = radius;
}

Circle.prototype.getDiameter = function () {
  // 이 시점에는 생성자 함수 자신이 생성할 인스턴스를 가리키는 식별자를 알 수 없다.
  return 2 * ????.radius;
};

// 생성자 함수로 인스턴스를 생성하려면 먼저 생성자 함수를 정의해야 한다.
const circle = new Circle(5);

 

생성자 함수를 정의하는 시점에는 아직 인스턴스가 생성되지 않았기 때문에 자신이 생성할 인스턴스를 가리키는 식별자를 알 수 없다. ⭐️

 

생성자 함수로 객체를 생성하려면 생성자 함수를 먼저 정의한 후 new연산자와 함께 생성자 함수를 호출해야 한다. 즉, 생성자 함수로 인스턴스를 생성하려면 먼저 생성자 함수가 존재해야 한다.

 

생성자 함수를 정의하는 시점에는 인스턴스를 가리키는 식별자를 알 수 없기 때문에 특수한 식별자를 사용한다. 바로 this이다.

this는 '자신이 속한 객체' 또는 '자신이 생성할 인스턴스'를 가리키는 자기 참조 변수(self-referenceing variable)다.

 

this는 자바스크립트 엔진에 의해 암묵적으로 생성되며, 코드 어디서든 참조할 수 있다. 함수를 호출하면 arguments객체와 this가 암묵적으로 함수 내부에 전달된다.

 

2. 함수 호출 방식과 this 바인딩

this가 가리키는 값, 즉 this바인딩은 함수 호출 방식에 의해 동적으로 결정된다. ⭐️

 

※ 렉시컬 스코프와 this 바인딩은 결정 시기가 다르다.
렉시컬 스코프는 함수 정의가 평가되어 함수 객체가 생성되는 시점에 결정된다.
this 는 함수가 호출시에 결정된다.

 

※ 함수 객체가 생성되는 시점
함수 선언문은 코드(함수 선언문을 포함한) 평가 단계에서 함수 객체 생성
함수 표현식은 코드(함수 표현식을 포함한) 실행 단계에서 함수 객체 생성

 

함수를 호출하는 다양한 방식

  • 일반 함수 호출
  • 메서드 호출
  • 생성자 함수 호출
  • Function.prototype.apply/call/bind메서드에 의한 간접 호출
// this 바인딩은 함수 호출 방식에 따라 동적으로 결정된다.
const foo = function () {
  console.dir(this);
};

// 동일한 함수도 다양한 방식으로 호출할 수 있다.

// 1. 일반 함수 호출
// foo 함수를 일반적인 방식으로 호출
// foo 함수 내부의 this는 전역 객체 window를 가리킨다.
foo(); // window

// 2. 메서드 호출
// foo 함수를 프로퍼티 값으로 할당하여 호출
// foo 함수 내부의 this는 메서드를 호출한 객체 obj를 가리킨다.
const obj = { foo };
obj.foo(); // obj

// 3. 생성자 함수 호출
// foo 함수를 new 연산자와 함께 생성자 함수로 호출
// foo 함수 내부의 this는 생성자 함수가 생성한 인스턴스를 가리킨다.
new foo(); // foo {}

// 4. Function.prototype.apply/call/bind 메서드에 의한 간접 호출
// foo 함수 내부의 this는 인수에 의해 결정된다.
const bar = { name: 'bar' };

foo.call(bar);   // bar
foo.apply(bar);  // bar
foo.bind(bar)(); // bar
  1. 일반 함수로 호출하는 경우 기본적으로 this에는 전역 객체가 바인딩된다.(strict mode에서는 undefined)
  2. 메서드 내부의 this에는 메서드를 호출한 객체가 바인딩된다.(메소드 소유가 아닌 '호출'한 객체)
  3. 생성자 함수 내부의 this에는 생성자 함수가 (미래에) 생성할 인스턴스가 바인딩된다.
  4. Function.prototype.apply/call/bind 메서드에 의한 간접 호출에서는 메서드에 첫 번째 인자로 전달된 객체가 바인딩된다.