
=> 생성자 함수 : 초기화 담당
=> 인스턴스 : 클래스에서 파생된 고유한 것, 실제로 생성된 후 메모리에 올라감

=> 메서드 : 객체(클래스)에서 행동을 뜻함

=> getter / setter : 필드에 접근할 권한을 가진 제어자
=> private 속성은 .연산자로 접근할 수 없다.
=> 비공개로 설정할 필요가 있는 속성을 private로 설정한 후, 이 속성에 접근하여 값을 읽거나, 쓰기 위한 Getter, Setter 함수를 사용하여 속성을 정의할 수 있다.
=> getter 있고 setter 없으면 속성은 자동으로 읽기 전용
=> setter 매개변수의 타입 없으면 getter의 반환 타입에서 추론

=> 파생이라는 클래스는 기본 클래스의 모든 속성을 가지고 있는 것이다.
=> 'Base' 출력
=> 상속

그런데 왜 'Base'는 어디가고 'Derived'만 출력되었냐..??
=> 기본 클래스에서 물려받은 것만 사용하는 것이 아님!!!
=> 파생된 클래스에서 정의된 메스드의 호출이 이루어짐!!(덮어씌워짐)
=> 확장
=> 기본 클래스 호출시 사용
=> 생성자에서 this 사용 전 호출되어야함

그런데 나는 기본 클래스의 내용도 재활용하고 싶다???

=> "동물의 이름은 Jang 사람의 이름은 Jang" 출력
=> 속성과 메서드에 접근을 제한해 안전하게 사용 가능
=> 클래스 내부 구현 정보를 적당히 공개하여 일부분만 노출시켜 API와 비슷한 흉내를 낼 수 있고 타입 스스템을 이용해 규칙을 강제할 수 있음
public : 어디서나 접근 가능(기본값)
protected : 해당 클래스와 서브클래스에서만 접근 가능
private : 해당 클래스의 인스턴스에서만 접근 가능


color는 private이기 때문에 자식 클래스에서 접근이 불가능하다.
그리고 year는 protected이기 때문에 자식 클래스에서는 접근이 가능하지만, 클래스 인스턴스에서는 접근이 불가능하다.
=> 클래스 속성과 메서드를 new로 인스턴스화하지 않고 호출 가능
=> 접근 제어자 활용가능

static을 붙이지 않는다면 접근이 불가능한 것을 알 수 있음.ㅇ
static을 붙이면 인스턴스화하지 않고도 접근 가능
만약에
static name = 'name'
라는 코드를 적어놓으면 실행이 되지 않는다. 왜냐!!!
클래스는 그 자체로 new로 호출할 수 있는 함수이기 때문
즉, name이라는 것은 built-in 속성인 Function.name과 충돌이 있기 때문!
=> readonly가 선언된 클래스 프로퍼티는 선언 시 또는 생성자 내부에서만 값 할당 가능
=> 그 외에는 값을 할당할 수 없고 오직 읽기만 가능한 상태가 됨 (재할당 금지)

이렇게 코드를 작성하면 너무 쉽게 재할당이 가능해진다.
하지만 readonly를 넣는다면??

재할당 불가능..
=> abstract를 선언한 클래스로 직접 인스턴스화 될 수 없는 클래스이다.
=> 직접 인스턴스화 될 수 없지만 extends 후 파생된 클래스를 인스턴스화하도록 유도한다.
=> 추상 클래스는 구현된 메서드를 포함시킬 수 있다.
=> abstract 선언한 메서드는 파생된 클래스에서 메서드를 구현해야한다.

파생된 모든 클래스가 hello()라는 메서드를 구현하게 하고 싶으면 abstract 키워드를 붙여주면 된다.
추상 클래스는 직접 인스턴스가 될 수 없지만, 파생된 클래스가 인스턴스화되는 것은 문제가 없음!!

필드를 만들어주고 생성자 매개변수를 또 만드는 것이 귀찮아!!!

이렇게 합쳐주면 가독성은 떨어지지만 복잡한 과정이 줄어듦
오버라이딩
=> 자식 클래스에서 부모 클래스의 기능(method)을 재정의할 때 사용
오버로딩
=> 동일한 이름을 가진 여러 개의 메서드를 만든 후 매개변수 타입과 개수에 맞는 메서드가 자동으로 호출되는 기능