[240405] 24장 클래스 (2)

24장 클래스 (2)

클래스의 인스턴스 생성 과정

  1. 인스턴스 생성과 this 바인딩
    • constructor 의 내부 코드가 실행되기전에 암묵적으로 빈 객체 생성 (클래스가 생성한 인스턴스임)
    • 인스턴스의 프로토타입으로 클래스의 prototype 프로퍼티가 가리키는 객체가 설정
    • 인스턴스는 암묵적으로 this 에 바인딩 된다.
    • constructor 내부의 this는 클래스가 생성한 인스턴스 가리킴
  2. 인스턴스 초기화
    • this에 바인딩 되어 있는 인스턴스 초기화
    • 프로퍼티를 추가하고 constructor가 인수로 전달받은 초기값으로 인스턴스의 프로퍼티 값을 초기화
    • 만약 constructor가 생략되었다면 이 과정도 생략
  3. 인스턴스 반환
    • 클래스의 모든 처리가 끝나면 완성된 인스턴스가 바인딩된 this 가 암묵적으로 반환됨
class Person {
	// 생성자
	constructor(name) {
		// 1. 암묵적으로 인스턴스가 생성되고 this에 바인딩된다.
		console.log(this); // Person {}
		console.log(Object.grtPrototypeOf(this) === Person.prototype); // true
		
		// 2. this에 바인딩되어 있는 인스턴스를 초기화
		this.name = name;
		
		// 3. 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환
		}
}

프로퍼티

1. 인스턴스 프로퍼티

  • constructor 내부에서 정의해야함
  • 이미 인스턴스가 생성되고 this 에 바인딩 되어있음

2. 접근자 프로퍼티

  • 자체적으로 값 [[Value]] 을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수로 구성된 프로퍼티
  • 클래스의 메서드는 기본적으로 프로토타입 메서드 → 클래스 접근자 프로퍼티 또한 프로토타입의 프로퍼티가 됨
class Person {
	constructor(firstName, lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}
	
	// getter 함수, 접근자 프로퍼티
	get fullName() {
		return `${this.firstName} ${this.lastName}`;
	}
	
	// setter 함수
	set fullName() {
		[this.firstName, this.lastName] = name.split(' ');
	}
}

3. 클래스 필드 정의 제안

  • 자바스크립트 클래스 몸체에는 메서드만 선언 가능했지만, 최신 브라우저에서는 정상 동작을 한다. (Chrome 72이상, Node.js 12이상)
  • ECMA 사양 관리하는 기술 위원회도 여럿인데 ECMA-262 사양을 관리를 담당하는 위원회가 TC39 다. 여기서 제안되어있음
class Person {
	// 클래스 필드 정의
	name = 'Lee';
}

const me = new Person();
console.log(me); // Person {name: "Lee"} 
  • this 는 constructor 와 메서드 내에서만 유효
  • 클래스 필드 참조할때 this 필수
  • 클래스 필드에 함수도 가능, 화살표 함수도 가능
    • 프로토타입 메서드가 아닌 인스턴스 메서드가 됨
    • 권장하지 않는다.
      class Person {
      	// 클래스 필드 정의
      	name = 'Lee';
        	
      	// 클래스 필드에 함수를 할당
      	getName = function () {
      		return this.name;
      	}
        	
      	// getName = () => this.Name;
      }
        
      const me = new Person();
      console.log(me); // Person {name: "Lee", getName: f }
      console.log(me.getName()); // Lee 
    

4. private 필드 정의 제안

class Person {
	// private 필드 정의
	// 반드시 몸체에 정의해야 함
	#name = '';
	constructor(name) {
		this.#name = name;
	}
}

const me = new Person('Lee');
// 외부에서는 참조할 수 없다.
console.log(me.#name); // SyntaxError
  • TS에서는 public private protected 모두 지원

5. static 필드 정의 제안

class MyMath {
	// static public 필드 정의
	static PI = 22/7;
}

상속에 의한 클래스 확장

1. 클래스 상속과 생성자 함수 상속

  • 클래스의 상속이란? 기존 클래스를 상속받아 새로운 클래스를 확장하여 정의
  • 프로토타입 기반의 상속은 프로토타입 체인을 통해 다른 객체의 자산을 상속 받는 것

2. extends 키워드

class Animal {}

// extends 키워드를 통해 상속
class Bird extends Animal {
	fly() { return 'fly'; }
}
  • 수퍼클래스와 서브클래스는 인스턴스 프로토타입 체인 뿐 아니라 클래스 간의 프로토타입 체인도 생성한다.

3. 동적 상속

  • 생성자 함수를 상속 받아 클래스 확장도 가능
  • [[Construct]] 내부 메서드를 갖는 함수 객체로 평가될 수 있는 모든 표현식 사용 가능
// 생성자 함수 
function Base() {}

class Derived extends Base{}
function Base1() {}

class Base2 {}

let condition = true; 

// 조건에 따라 동적으로 상속 대상을 결정하는 서브클래스
class Derived extends (condition ? Base1 : Base2) {}

4. 서브클래스의 constructor

class Base {}

class Derived extends Base {
	// 생략하면 암묵적으로 정의됨
	constructor(..args) { super(...args); }
}

5. super 키워드

  • this 와 같이 특수한 키워드임
  • super 를 호출하면 수퍼클래스의 constructor 를 호출
  • super를 참조하면 수퍼클래스의 메서드를 호출할 수 있다.

주의사항

  • 서브클래스에서 constructor 를 생략하지 않은 경우 반드시 super 호출해야한다.
  • 서브클래스 constructor 에서 super 를 호출하기 전에는 this 를 참조할 수 없다.
  • super 는 서브클래스의 constructor 에서만 호출 된다.

super 참조

  • 서브클래스 프로토타입 메서드 내에서 super.sayHi 는 수퍼클래스의 프로토타입 메서드 sayHi를 가리킨다.
  • 메서드는 [[HomeObject]] 내부슬롯을 가짐
    • 자신을 바인딩하고 있는 객체를 가리킴
    • 메서드 축약 표현으로 정의된 함수만이 갖고 있음
const obj = {
	// foo 는 ES6의 메서드 축약 표현으로 정의한 메서드
	// HomeObject를 갖는다. 
	foo() {} ,
	
	// 일반함수이므로 갖고 있지 않음
	bar: function () {} 
}
  • 메서드 축약 표현으로 정의된 함수는 super 사용 가능
const base = {
	name: 'Lee',
	sayHi() {
		return `Hi! ${this.name}`;
	}
};

const derived = {
	__proto__: base,
	sayHi() {
		return `${super.sayHi()}`;
	}
};

6. 상속 클래스의 인스턴스 생성 과정

  1. 서브 클래스의 super 호출
    • 수퍼, 서브 클래스 구별하기 위해 [[ConstructorKind]] 갖는다. 상속 안받으면 “base 설정” 받으면 받은걸로 설정
    • 서브클래스는 자신이 직접 인스턴스를 생성하지 않고 수퍼클래스에게 인스턴스 생성을 위임한다. 이게 바로 서브 클래스의 constructor 에서 super를 호출해야하는 이유다.
  2. 수퍼클래스의 인스턴스 생성과 this 바인딩
    • 암묵적으로 빈 객체 생성 (클래스 인스턴스)
    • this 바인딩
    • —> 수퍼클래스가 생성함
    • new.target은 서브 클래스 가리킴 , 생성된건 얘가 생성됨
  3. 수퍼클래스의 인스턴스 초기화
  4. 서브 클래스 constructor 복귀과 this 바인딩
    • 별도의 인스턴스 생성하지 않고 super 가 반환한 인스턴스를 this 에 바인딩함
  5. 서브클래스의 인스턴스 초기화
  6. 인스턴스 반환

7. 표준 빌트인 생성자 함수 확장

  • [[Construct]] 내부 메서드를 갖는 함수 객체로 평가 가능한 표현식도 extends 사용 가능
  • 빌드인 객체도 사용 가능
class MyArray extends Array {} 

Categories:

Updated:

Leave a comment