이번 정리 목차는 25장이다.
25장 클래스
클래스는 프로토타입의 문법적 설탕인가?
- JS는 프로토타입 기반 객체지향언어
- 객체지향 프로그래밍에 익숙한 프로그래머가 빠르게 학습할 수 있도록 하기위한 새로운 객체 생성 메커니즘이 클래스이다.
- 클래스는 함수이며 기존 프로토타입 기반 패턴을 클래스 기반 패턴처럼 사용할 수 있도록 한 것
- 클래스와 생성자 함수 모두 프로토타입 기반 인스턴스를 생성하지만 동작은 다름
- 클래스는 new연산자 없이 호출하면 에러
- Extends와 super 키워드 제공
- 호이스팅이 발생하지 않는 것처럼 동작, 변수 호이스팅 발생
- 암묵적 strict모드 지정
- constructor, 프로토타입 메서드, 정적 메서드 모두 열거되지 않음,
- [[Enumerable]] false
클래스 정의
- class 키워드 사용하여 정의, 클래스 이름은 파스칼 케이스 사용이 일반적
- 표현식으로도 클래스 정의 가능, 기명, 무명 다 가능
- 클래스도 일급 객체
- 몸체에는 0개 이상의 메서드만 정의 가능(constructor, 프로토타입 메서드, 정적 메서드)
- 생성자 함수의 정의 방식과 매우 유사!!
클래스 호이스팅
- 클래스는 함수로 평가
- 런타임 이전에 먼저 평가되어 함수 객체 생성
- 함수 객체는 constructor, 프로토타입도 더불어 생성
- 클래스는 정의 이전에 참조 X
- let, const 같은 변수 호이스팅이 발생하기 때문에 호이스팅이 발생하지 않는 것처럼 동작
인스턴스 생성
- 클래스는 생성자 함수이며 new 연산자와 함께 호출되어 인스턴스 생성
- 인스턴스 생성하는 것이 유일한 존재 이유이므로 반드시 new와 함께 호출
- 클래스 표현식으로 정의된 클래스는 식별자를 사용하여 인스턴스 생성해야 함
메서드
- 클래스 몸체에는 0개 이상의 메서드만 선언 가능
- constructor(생성자), 프로토타입 메서드, 정적 메서드
[constructor]
- 인스턴스를 생성하고 초기화 하기 위한 특수한 메서드
- 이름 변경 불가
- 메서드로 해석되는 것이 아닌 constructor의 기술된 동작을 하는 함수 객체가 생성
- 클래스 내에 최대 한 개만 존재
- constructor생략 가능, 생략하면 빈 constructor 암묵적 정의되어 빈 객체 생성
- 클래스 외부에서 인스턴스 프로퍼티의 초기값 전달하려면 constructor에 매개변수 선언하고 인스턴스 생성 시 초기값 전달한다.
- 인스턴스를 초기화 하려면 constructor 생략해서는 안됨
- 별도의 반환문을 갖지 않아야 함. 암묵적 this 반환하기 때문
[프로토타입 메서드]
- 생성자 함수와 다르게 prototype 프로퍼티에 메서드 추가하지 않아도 기본적으로 프로토타입 메서드가 됨(Person.prototype.sayHi말고 sayHi()하면 됨)
- 클래스가 생성한 인스턴스는 프로토타입 체인의 일원이 됨
- 인스턴스는 프로토타입 메서드 상속받아 사용할 수 있다.
[정적 메서드]
- 인스턴스를 생성하지 않아도 호출할 수 있는 메서드
- 클래스에서 메서드에 static 키워드 붙이면 정적 메서드가 됨(static sayHi())
- 정적 메서드는 클래스에 바인딩 됨
- 인스턴스로 호출되지 않고 클래스로 호출(인스턴스로는 호출할 수 없음)
[정적 메서드와 프로토타입 메서드 차이]
- 자신이 속해있는 프로토타입 체인이 다름
- 정적 메서드는 클래스로 호출, 프로토타입 메서드는 인스턴스로 호출
- 정적 메서드는 인스턴스 프로퍼티(this 사용 안함)를 참조할 수 없지만 프로토타입 메서드는 인스턴스 프로퍼티(this사용)를 참조할 수 있다.
[클래스에서 정의한 메서드 특징]
- function 키워드 생략한 메서드 축약 표현 사용
- 객체 리터럴과 다르게 메서드 정의할 때 콤마 필요 X
- 암묵적으로 strict 모드 실행
- for…in문이나 Object.keys메서드 등으로 열거 불가
- 내부 메서드[[Construct]]를 갖지 않는 non-constructor이므로 new 연산자와 함께 호출 불가
클래스의 인스턴스 생성 과정
[인스턴스 생성과 this 바인딩]
- 클래스 호출하면 암묵적으로 빈 객체(인스턴스)가 생성되고 인스턴스는 this에 바인딩
- constructor 내부의 this는 클래스가 생성한 인스턴스 가리킴
[인스턴스 초기화]
- constructor의 내부 코드가 실행되어 this에 바인딩되어 있는 인스턴스 초기화
[인스턴스 반환]
- 클래스의 모든 처리가 끝나면 this 반환
프로퍼티
[인스턴스 프로퍼티]
- constructor 내부에 정의, 언제나 public
[접근자 프로퍼티]
- 클래스에서도 사용가능
- getter와 setter는 호출하는 것이 아니라 프로퍼티처럼 참조 형식으로 사용
- setter는 단 하나의 값만 할당 받기 때문에 단 하나의 매개변수만 선언 가능
[클래스 필드 정의 제안]
- 클래스가 생성할 인스턴스의 프로퍼티를 클래스 필드라 한다.
- js에서 프로퍼티를 추가하려면 constructor 내부에서 this에 프로퍼티 추가해야 하고 참조하려면 this를 사용해서 참조해야 하며 몸체에는 메서드만 선언할 수 있는데 js에서도 클래스기반 객체지향 언어의 클래스 필드처럼 정의할 수 있는 새로운 표준 사양을 TC39프로세스의 stage3에 제안되어 있음 -> 최신 브라우저와 최신 node.js는 선제적으로 미리 구현 해 놓음
- 몸체에서 클래스 필드를 정의하는 경우 this에 클래스 필드 바인딩 X
- 클래스 필드 참조할 경우 this 반드시 사용
- 클래스 필드에 초기값 할당하지 않으면 undefined
- 클래스 필드에 함수 할당 가능 하지만 인스턴스 메서드가 되므로 권장 X
- 인스턴스를 생성할 때 외부 초기값으로 클래스 필드를 초기화할 필요가 있다면 constructor에서 인스턴스 프로퍼티 정의하는 기존 방식 사용하고 인스턴스 생성할 때 외부 초기값으로 클래스 필드 초기화할 필요 없으면 기존 방식과 클래스 필드 정의제안 모두 사용 가능
[private 필드 정의 제안]
- js는 캡슐화를 완전하게 지원 X
- class도 접근 제한자 지원 X, 언제나 인스턴스 프로퍼티는 public
- TC39프로세스의 stage3에 private 필드를 정의할 수 있는 새로운 표준 사양이 제안되어 있고 최신 브라우저와 node.js에서는 이미 구현되어 있다
- private 필드의 선두에는 #을 붙여주고 private 필드를 참조할 때도 #을 붙여준다.
- EX) #name = “”, this.#name
- private필드는 클래스 내부에서만 참조 가능, 접근자 프로퍼티 통해 간접적 외부 접근 가능
- 반드시 private 필드는 클래스 몸체에 정의, constructor정의하면 에러
[static 필드 정의 제안]
- static public 필드, static private 필드, static private 메서드 정의할 수 있는 새로운 표준 사양이 TC39프로세스의 stage3에 제안되어 있다
- 이 중에서 static public / static private 필드는 최신 브라우저와 node.js 이미 구현
상속에 의한 클래스 확장
- 상속에 의한 클래스 확장은 기존 클래스를 상속받아 새로운 클래스를 확장하여 정의하는 것
- 코드 재사용 관점에서 매우 유용
[extends 키워드]
- extends 키워드로 상속받을 클래스를 정의
- 상속을 통해 확장된 클래스는 서브 클래스, 서브클래스에게 상속된 클래스를 수퍼클래스
- extends 키워드 역할은 수퍼클래스와 서브클래스 간의 상속 관계를 설정하는 것
- 클래스도 프로토타입을 통해 상속 관계 구현
- 수퍼클래스와 서브클래스는 인스턴스 프로토타입 체인뿐만 아니라 클래스 간 프로토타입 체인도 생성하므로 프로토타입 메서드, 정적 메서드 모두 상속 가능
[동적 상속]
- extends 키워드는 클래스뿐만 아니라 생성자 함수를 상속받아 확장 가능, 단 반드시 extends 키워드 앞에는 클래스가 와야 함
- extends 키워드 다음에는 [[Construct]] 내부 메서드를 갖는 함수 객체로 평가될 수 있는 모든 표현식을 사용할 수 있다. 이를 통해 동적으로 상속받을 대상 결정 가능
[서브클래스의 constructor]
- 서브클래에서 constructor 생략하면 constructor에 constructor(…args) {super(args);}가 암묵적으로 정의
- args(new 연산자와 함께 클래스 호출할 때 전달할 인수의 리스트)가 암묵적 정의
- super()는 수퍼클래스의 consructor를 호출하여 인스턴스 생성
[super 키워드]
- super 키워드는 함수처럼 호출할 수도 있고 this와 같이 식별자처럼 참조할 수 있는 특수한 키워드
- super 호출하면 수퍼클래스의 constructor를 호출
- super를 참조하면 수퍼클래스의 메서드 호출
[super 호출]
- 서브클래스에서 constructor 생략하지 않는 경우 반드시 super 호출해야 함
- 서브클래스의 constructor에서 super 호출하기 전에는 this 참조 불가
- super는 반드시 서브클래스의 constructor에서만 호출한다.
[super 참조]
- 메서드 내에서 super 참조하면 수퍼클래스의 메서드를 호출할 수 있다.
- [[HomeObject]]를 갖는 ES6의 메서드 축약표현으로 정의된 함수만이 super 참조 가능
상속 클래스의 인스턴스 생성 과정
[서브클래스의 super 호출]
- 엔진은 수퍼클래스와 서브클래스 구분 위해 [[ConstructorKind]]내부 슬롯을 갖고 이 내부슬롯에 수퍼클래스면 base, 서브클래스는 derived로 설정됨
- 서브클래스는 자신이 직접 인스턴스 생성하지 않고 수퍼클래스에게 인스턴스 생성을 위임, 이것이 바로 서브클래스의 constructor에서 반드시 super 호출해야 하는 이유!!
[수퍼클래스의 인스턴스 생성과 this 바인딩]
- 수퍼클래스 constructor 내부 코드 실행 이전에 암묵적 빈 객체(인스턴스) 생성하고 this 바인딩
- 인스턴스는 수퍼클래스가 생성 했지만 new.target은 서브클래스를 가리킨다!! 그러므로 인스턴스의 프로토타입은 서브클래스를 따른다!!
[수퍼클래스 인스턴스 초기화]
- constructor가 실행되어 this에 바인딩되어 있는 인스턴스 초기화
[서브클래스 constructor로 복귀와 this 바인딩]
- super 호출 종료되고 서브클래스 constructor로 돌아온다.
- 이때 super가 반환한 인스턴가 this에 바인딩 된다. 서브클래스는 별도의 인스턴스 생성하지 않고 super가 반환한 인스턴스를 this에 바인딩하여 그대로 사용, 이처럼 super가 호출되지 않으면 인스턴스 생성이 되지 않고 this 바인딩도 할 수 없다. 이 때문에 서브클래스의 constructor에서 super를 호출하기 전에는 this를 참조할 수 없는 이유가 바로 이 때문이다!!
[서브클래스의 인스턴스 초기화]
- 서브클래스의 constructor의 기술되어 있는 인스턴스 초기화 실행
[인스턴스 반환]
- 클래스의 모든 처리가 끝나면 완성된 인스턴스가 바인딩된 this가 암묵적 반환
표준 빌트인 생성자 함수 확장
- extends 키워드 다음에 String, Number, Array 같은 표준 빌트인 객체도 [[Construct]]내부 메서드를 갖는 생성자 함수 이므로 사용하여 확장할 수 있다.
'JS DeepDive' 카테고리의 다른 글
모던 자바스크립트 DeepDive 공부 내용 13차 (0) | 2023.05.08 |
---|---|
모던 자바스크립트 DeepDive 공부 내용 12차 (1) | 2023.05.08 |
모던 자바스크립트 DeepDive 공부 내용 10차 (0) | 2023.05.08 |
모던 자바스크립트 DeepDive 공부 내용 9차 (0) | 2023.05.08 |
모던 자바스크립트 DeepDive 공부 내용 8차 (0) | 2023.05.08 |