25.1 클래스는 프로토타입의 문법적 설탕인가?
- JS는 프로토타입 기반의 객체 지향 언어 (클래스 필요없는, class free)
- 과거 ES5 생성자 함수와 프로토타입을 이용하여 객체지향 언어의 상속 구현 가능했음
- 클래스는 사실 함수임, 기존 프로토타입 기반 패턴을 클래스 기반 패턴처럼 사용 가능한
문법적 설탕 (Syntactic sugar)이라고도 볼 수 있음 => 새로운 객체 생성 메커니즘으로 보는 것이 적절
- 클래스와 생성자 함수 모두 프로토타입 기반 인스턴스 생성, 하지만 정확히 동일하게 동작하지 않음
- 클래스는 생성자 함수보다 엄격하고, 추가 기능 제공
- ES6 클래스; extends, super 키워드 제공, new 연산자 없이 호출하면 에러 발생,
클래스 호이스팅 발생하지 않는 것 처럼 동작, 클래스 내 모든 코드에 암묵적 strict mode 적용,
클래스의 모든 멤버 변수와 함수는 열거 불가
25.2 클래스 정의
- class 키워드 사용해서 정의 (파스칼 케이스)
- 사실 클래스도 표현식으로 정의할 수 있음 (변수에 할당 가능, 익명/기명 클래스 표현식)
- 클래스는 값처럼 사용할 수 있는 '일급 객체'
- 클래스 몸체에서 정의할 수 있는 3가지 메서드
- constructor (생성자)
- 프로토타입 메서드
- 정적 메서드
25.3 클래스 호이스팅
- 클래스는 함수로 평가됨
- 런타임 이전에 먼저 평가되어 함수 객체 생성 (constructor, 생성자 함수로서 호출 가능)
- 프로토타입도 더불어 생성됨
- 프로토타입과 생성자 함수는 항상 쌍으로 존재
- 클래스는 정의 이전에 참조 불가
- 클래스는 호이스팅이 발생하지 않는 것 처럼 보임
- 클래스는 let, const 키워드로 선언한 변수처럼 호이스팅됨 (TDZ)
- 모든 식별자는 호이스팅됨 (모든 선언문은 런타임 이전에 먼저 평가되기 때문)
25.4 인스턴스 생성
- 클래스는 생성자 함수, new 연산자와 함께 호출되어 인스턴스 생성
- new 연산자 없이 호출하면 TypeError 발생
25.5 메서드
- constructor
- 인스턴스를 생성하고 초기화하기 위한 특수한 메서드 (이름 변경 불가)
- 클래스도 함수 객체 고유의 프로퍼티 모두 가지고 있음
- constructor 내부의 this는 클래스가 생성한 인스턴스 가리킴
- 클래스의 constructor와 프로토타입의 constructor 프로퍼티는 관련 없음,
프로토타입의 constructor 프로퍼티는 모든 프로토타입이 가지고 있는 프로퍼티, 생성자 함수 가리킴
- 클래스 내에 constructor는 최대 한 개만 존재 가능 (초과 시 SyntaxError 발생)
- constructor는 생략 가능 (빈 객체가 암묵적으로 정의됨)
- constructor 에는 return문 없어야 함 (암묵적으로 this (인스턴스) 반환함)
- 프로토타입 메서드
- 생성자 함수처럼 굳이 '생성자함수명.prototype.메서드' 이렇게 설정할 필요 없음
- 메서드 이름만 가지고 바로 선언해도 기본적으로 프로토타입 메서드가 됨
- 클래스가 생성한 인스턴스는 프로토타입 체인의 일원이 됨
- 인스턴스는 프로토타입 메서드 상속받아 사용 가능
- 정적 메서드
- 인스턴스를 생성하지 않아도 호출할 수 있는 메서드
- 클래스 내에 메서드 앞에 static 키워드 붙이기 (클래스 메서드)
- 클래스에 바인딩된 메서드가 됨
- 클래스로 호출
- 정적 메서드는 인스턴스로 호출 불가
- 정적 메서드가 바인딩된 클래스는 인스턴스의 프로토타입 체인상에 존재하지 않음
- 정적 메서드와 프로토타입 메서드의 차이
- 프로토타입 체인이 다름
- 정적 메서드는 클래스로 호출하고, 프로토타입 메서드는 인스턴스로 호출함
- 정적 메서드는 인스턴스 프로퍼티 참조 불가, 프로토타입 메서드는 인스턴스 프로퍼티 참조 가능
- 정적 메서드 내에서 this 키워드 사용 X
- 메서드 내에서의 this는 메서드를 소유한 객체가 아니라 호출한 객체에 바인딩됨 (this 바인딩 다름)
- 프로토타입 메서드는 인스턴스로 호출하므로 this는 인스턴스 가리킴
- 정적 메서드는 클래스로 호출해야 하므로 this는 클래스를 가리킴
- 클래스에서 정의한 메서드의 특징
- function 키워드 생략한 메서드 축약 표현 사용
- 객체 리터럴과 다르게 콤마 사용 필요 X
- 암묵적으로 strict mode 사용
- for ... in 문이나 Object.keys()로 열거 불가
- non-construtor, 메서드는 new 연산자로 호출 불가
25.6 클래스의 인스턴스 생성 과정
- new 연산자와 함께 클래스 호출하면 클래스의 내부 메서드 [[Construct]]가 호출됨
- 인스턴스 생성과 this 바인딩
- new 연산자로 클래스 호출 시 constructor 내부 코드 실행 전에,
암묵적으로 빈 객체 생성됨 (클래스가 생성한 인스턴스)
- 클래스가 생성한 인스턴스의 프로토타입으로 클래스의 prototype 프로퍼티가 가리키는 객체가 설정됨
- 인스턴스는 this에 바인딩됨
- 인스턴스 초기화
- this에 바인딩되어 있는 인스턴스 초기화 (프로퍼티 추가, 매개값으로 받은 것을 할당하여 초기화)
- 인스턴스 반환
- 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환됨
25.7 프로퍼티
- 인스턴스 프로퍼티
- constructor 내부에서 정의해야 함
- JS에서는 접근 제한자 지원 X
- 기본적으로 인스턴스 프로퍼티는 언제나 public
- 접근자 프로퍼티
- 자체적으로 값([[Value]] 내부 슬롯)을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나,
저장할 때 사용하는 접근자 함수로 구성된 프로퍼티
- 접근자 프로퍼티는 get, set, enumerable, configurable 프로퍼티 어트리뷰트 가짐
- get 함수이름() {}, set 함수이름() {}
- getter/setter 함수
- 함수 이름이 인스턴스 프로퍼티처럼 사용됨 (호출하는 방식 아님)
- 클래스의 접근자 프로퍼티 또한 인스턴스 프로퍼티가 아닌 프로토타입의 프로퍼티가 됨
- 클래스 필드 정의 제안
- 클래스가 생성할 인스턴스의 프로퍼티를 가리키는 용어 (필드, 멤버)
- Class field declarations
- 인스턴스 프로퍼티를 마치 클래스 기반 언어의 필드처럼 정의 가능
- this 사용하면 안됨 (this는 constructor와 메서드 내에선만 사용 가능)
- 함수는 일급 객체이므로 클래스 필드에 할당 가능 (화살표 함수, 함수 표현식 가능),
이 함수는 프로토타입 메서드가 아닌 인스턴스 메서드가 됨 (권장 X)
- 모든 클래스 필드는 인스턴스 프로퍼티가 됨
- 클래스 필드에 화살표 함수 할당하여 화살표 함수 내부의 this가 인스턴스 가리키게 할 수 있음
- 이벤트 핸들러 내부의 this는 DOM 요소를 가리킴
- 화살표 함수 내부의 this는 항상 상위 컨텍스트의 this를 가리킴
- private 필드 정의 제안
- 인스턴스 프로퍼티는 인스턴스를 통해 클래스 외부에서 언제나 참조 가능 (public)
- 클래스 필드도 기본적으로 public
- private 필드 앞에 # 붙이면 private로 적용됨 (사용할 때도 # 붙이면서 해야 함)
- 클래스 내부에서만 참조 가능 (클래스 외부에서 참조 불가)
- 접근자 프로퍼티를 통해 간접적으로 접근은 가능
- private 필드는 constructor에 정의하면 SyntaxError 발생, 클래스 몸체에 정의해야 함
- 타입스크립트는 접근 제한자 모두 지원 (JS의 superset)
- static 필드 정의 제안
- static public 필드 (static 키워드 이용)
- static private 필드 (static 키워드와 # 이용)
25.8 상속에 의한 클래스 확장
- 클래스 상속과 생성자 함수 상속
- 생성자 함수 상속; 프로토타입 기반 상속은 프로토타입 체인 통해 다른 객체의 자산 상속받는 개념
- 생성자 함수는 상속을 통해 다른 생성자 함수 확장하는 문법 없음
- 과거 pseudo classical inheritance 패턴 있긴 했음
- 클래스 상속; 기존 클래스를 상속받아 새로운 클래스 extends (확장)하여 정의
- 상속에 의한 클래스 확장은 코드 재사용 관점에서 매우 유용
- extends 키워드
- extends 키워드 우측에 상속 받을 클래스 정의
- Super/Base/Parent 클래스 - Sub/Derived/Child 클래스
- 클래스도 프로토타입 통해 상속 관계 구현
- 클래스 간 프로토타입 체인, 인스턴스 간 프로토타입 체인 모두 생성됨,
=> 프로토타입 메서드, 정적 메서드 모두 상속 가능
- 동적 상속
- 클래스가 생성자 함수 상속받아 클래스 확장 가능 (extends 키워드 사용)
- 클래스 extends [[Construct]] 내부 메서드 갖는 함수 객체로 평가될 수 있는 모든 표현식 사용 가능
- 동적으로 상속받을 대상 결정 가능
- sub 클래스의 constructor
- 클래스에서 constructor 생략하면 비어 있는 constructor 암묵적으로 정의됨
- sub 클래스에서 constructor 생략하면, constructor(...args) { super(...args}; } 암묵적으로 정의됨
- super 클래스와 sub 클래스 모두 constructor 생략하면 빈 객체 생성됨
- super 키워드
- super 키워드는 함수처럼 호출 가능, 식별자처럼 참조도 가능
- super 호출
- super 호출 시, super 클래스의 constructor(super-constructor) 호출
- sub 클래스에서 constructor 생략 안하면 반드시 super 호출해야 함
- sub 클래스의 constructor에서 super 호출 전에는 this 참조 불가
- super는 반드시 sub 클래스의 constructor에서만 호출
- super 참조
- super 참조 시, super 클래스의 메서드 호출 가능
- ES6 축약 메서드는 내부 슬롯 [[HomeObject]] 가지며, 자신을 바인딩하고 있는 객체 가리킴
- [[Home Object]] 가지는 sub 클래스의 메서드에서 super 참조 가능
- 객체 리터럴에서도 super 참조 가능 (ES6 메서드 축약만 가능)
- sub 클래스의 정적 메서드에서 super.정적메서드 은 super 클래스의 동일한 이름의 정적 메서드 가리킴
- 상속 클래스의 인스턴스 생성 과정
- sub 클래스의 super 호출
- JS 엔진은 super 클래스와 sub 클래스 구분 위해 base 또는 derived 값 갖는 내부 슬롯 [[ConstructorKind]] 가짐
- sub 클래스는 자신이 직접 인스턴스 생성하지 않고 super 클래스에게 인스턴스 생성 위임
- sub 클래스 constructor에서 반드시 super를 호출해야 함
- super 클래스의 인스턴스 생성과 this 바인딩
- super 클래스 constructor 내부 코드 실행 전에 암묵적으로 빈 객체 생성
- 이 빈 객체가 아직 미완성된 인스턴스임, this에 바인딩됨
- new.target은 new 연산자와 함께 호출된 서브 클래스를 따라감 (비록 super 클래스에서 만들었지만)
- 생성된 인스턴스의 프로토타입은 서브 클래스의 prototype 프로퍼티가 가리키는 객체임
- super 클래스의 인스턴스 초기화
- sub 클래스 constructor로의 복귀와 this 바인딩
- super가 반환한 인스턴스가 this에 바인딩됨
- sub 클래스는 별도의 인스턴스 생성하지 않고 super가 반환한 인스턴스를 this에 바인딩하여 그대로 사용
- sub 클래스의 인스턴스 초기화
- 인스턴스 반환
- 완성된 인스턴스가 바인딩된 this 암묵적으로 반환
- 표준 빌트인 생성자 함수 확장
- String, Number, Array 같은 표준 빌트인 객체도 [[Construct]] 내부 메서드 갖는 생성자 함수이므로
extends 키워드 사용하여 확장 가능
- 나만의 원하는 메서드 만들어서 활용 가능
'Books > 모던 JS Deep Dive ✔️' 카테고리의 다른 글
[모던 JS Deep Dive] 27장 - 배열 (0) | 2022.01.14 |
---|---|
[모던 JS Deep Dive] 26장 - ES6 함수의 추가 기능 (0) | 2022.01.11 |
[모던 JS Deep Dive] 24장 - 클로저 (0) | 2022.01.06 |
[모던 JS Deep Dive] 23장 - 실행 컨텍스트 (0) | 2022.01.04 |
[모던 JS Deep Dive] 22장 - this (0) | 2022.01.03 |
댓글