이번 정리 목차는 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

 

[접근자 프로퍼티]

-       클래스에서도 사용가능

-       gettersetter는 호출하는 것이 아니라 프로퍼티처럼 참조 형식으로 사용

-       setter는 단 하나의 값만 할당 받기 때문에 단 하나의 매개변수만 선언 가능

 

[클래스 필드 정의 제안]

-       클래스가 생성할 인스턴스의 프로퍼티를 클래스 필드라 한다.

-       js에서 프로퍼티를 추가하려면 constructor 내부에서 this에 프로퍼티 추가해야 하고 참조하려면 this를 사용해서 참조해야 하며 몸체에는 메서드만 선언할 수 있는데 js에서도 클래스기반 객체지향 언어의 클래스 필드처럼 정의할 수 있는 새로운 표준 사양을 TC39프로세스의 stage3에 제안되어 있음 -> 최신 브라우저와 최신 node.js는 선제적으로 미리 구현 해 놓음

-       몸체에서 클래스 필드를 정의하는 경우 this에 클래스 필드 바인딩 X

-       클래스 필드 참조할 경우 this 반드시 사용

-       클래스 필드에 초기값 할당하지 않으면 undefined

-       클래스 필드에 함수 할당 가능 하지만 인스턴스 메서드가 되므로 권장 X

-       인스턴스를 생성할 때 외부 초기값으로 클래스 필드를 초기화할 필요가 있다면 constructor에서 인스턴스 프로퍼티 정의하는 기존 방식 사용하고 인스턴스 생성할 때 외부 초기값으로 클래스 필드 초기화할 필요 없으면 기존 방식과 클래스 필드 정의제안 모두 사용 가능

 

[private 필드 정의 제안]

-       js는 캡슐화를 완전하게 지원 X

-       class도 접근 제한자 지원 X, 언제나 인스턴스 프로퍼티는 public

-       TC39프로세스의 stage3private 필드를 정의할 수 있는 새로운 표준 사양이 제안되어 있고 최신 브라우저와 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 생략하면 constructorconstructor(…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]]내부 메서드를 갖는 생성자 함수 이므로 사용하여 확장할 수 있다.