기존의 프로토타입(prototype)방식을 좀 더 명료하게 사용할 수 있도록 돕는 일종의 도우미 라고 생각하는 것이 좋다.
클래스를 만드는 방식에는 2가지가 있다. 1. 선언적 방식 2. class 표현식을 변수에 할당
생성자(constructor) 함수를 통해 객체를 만들때도 함수에 인자로 넣어서, 외부에서 객체를 생성할때 안으로 넣어줄 수 있는 기능이 있는데, class에서도 마찬가지로 이런 기능이있다. 바로 생성자이다. 이것을 이용해서 최초의 초기값을 객체 안으로 넣어줄 수 있는 기능을 제공한다.
즉, A는 생성됐고, B는 생성될때 constructor가 한 번 불렸다는 것을 log찍은 것을 통해 알 수 있다.
따라서 우리가 보통 생성자를 사용해서 무언가를 인자로 넣어서 객체안에서 활용할 수 있도록 설정을 하게되는데
이처럼 동작이 되는 것을 알 수 있으며, 인자값을 안넣을 경우 자료형에서 배웠던 것 처럼 undefined 라고 뜨는것을 확인 할 수 있다.
멤버변수 보통 function으로 객체를 만들때도 그 안에서 this.변수 이름을만들고, 거기에 값을 넣어서 설정 하게된다. 이런것을 class에서는 좀 더 명확하고, 쉽게 할 수 있다.
//멤버변수 --constructor에서 객체 property를 할당해주는 방법
class A {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
console.log(new A("Mark", 37));
//class field는 런타임 확인 --위보다 더 쉽게 제공해주는 방식
class B {
name; //===this.name
age; //===this.age
}
console.log(new B());
class C {
name = "no name"; //초기값 설정
age = 0;
constructor(name, age) {
this.name = name;
this.age = age;
}
}
console.log(new C("Mark", 37));
console.log(new C());
위와 같은 문법을 사용할때는 node12버전 or 크롬 최신버전에서만 가능한데, 만약 그 이하버전이라면 SyntaxError: Unexpected token; 이라는 Error 메시지를 출력한다. 즉, 문법적인 오류가 나는 이유는 지금 이 문법(클래스에 필드를 직접 써주는 방식)을 이해하지 못하는 Runtime이라서 그렇다. 따라서 이렇게 직접 써주는 방식은 자기자신의 Runtime환경이 지원이 되는지 안되는지 확인한다.
nvm을 사용해서 Runtime을 바꾸기 명령어 : $ nvm use 12.11.1
또한, 보통 상위문법을 이해할 수 있는 문법으로 바꿔주는 역할을 하는 중간단계인 바벨을 많이 사용하게 될텐데 일단은 위와같은 문법이 안될 경우에는 이 문법을 지원하는 상황인지를 체크해보는게 좋다.
멤버함수
맨아래 class B처럼 함수를 만들고, 함수에서 객체가 가지고있는 자원들을 활용하여 로직을 만들 어 낼 수 있다.
get, set(게터, 세터) 클래스 안에서 get, set이라는 키워드를 이용해서 getter , setter을 만들어보자
이런일이 왜 생길까? class A에서 _name (문법적으로 강제는 아니지만, 언더바 _를 달게되는 경우는 내부적으로 쓸 경우는 _(언더바)를 달고, 멤버변수로 등재하고 get , set은 외부에서 접근할 수 있는 public한 접근 제어자가 된다 그래서 보통은 23번째 줄 처럼 a._name와 같은 직접적으로 바뀌는 행위는 하지않고 get, set을 통해서만 멤버변수를 바꾸는 형식으로 로직을 만든다.
그래서 readonly를 표현 할 수 있게 되는데, set에서의 역할을 함수는 작성하지않고, getter만 두게된다.
콘솔로 찍은 결과 처음에도 no name 이였는데, 나중에 set이 된 후에도 no name인것을 확인할 수 있다. 이는 set함수가 없기때문에 마치 readonly처럼 동작하게되는 것이다.
또한 다시 언급하자면 클래스 필드에있는 _name과 같은 언더바가 있을경우는 "외부에서 값을 바꾸지 말자!" 라는 약속이 되어있는 경우에 의미가 생기는 것이다.
+ 다른 예제로 더 알아보자!
아래와 getter함수를 설정해보겠다.
※함수앞에 get라고 붙여줘야하며, getter함수에서는 어떤 값을 무조건 반환해줘야한다.
왜냐하면 조회할 때마다 계산하는 것이 아니라 값이 바뀔때 마다만 계산하기때문에 아까 사용한 값을 재사용 하게된다.
코드로 더 쉽게 풀어보자면,
만약 setter함수와 getter함수를 만들지 않고, 하나의 getter함수만 사용했다면
위와 동작이 다르게 진행되는데,
결과 값을 보면, get sum( )이라는 함수가 조회 할 때 마다 sum ,sum, sum..이 호출되는것을 확인 할 수 있다.
따라서 정리해보자면, 아까의 코드와 지금의 코드의 차이점은
아까의 코드는 set함수 즉 값이 바뀔때만 합을 구했는데, 지금의 코드는 조회 할 때마다 합을 구하고있다.
(굳이 다시 더할 필요없이 아까했던거 다시 조회해서 쓰면될 것 같은데)
그래서 지금의 코드가 되게 비효율적이라고 생각된다.
getter : 특정값을 조회할때마다 어떤 함수를 호출하는 것이고,
setter : 특정값을 설정할때마다 value를 파라미터로 받아와서 어떤값을 설정할 수도있고, 추가적으로 어떤 코드를 실행할 수도있다. setter 예) set b(value) { this._b = value; this.calculate(); },
static 변수, 함수 (객체가 아니고, 클래스의 변수와 함수) >class를 new클래스 명으로해서 객체로 생성한다음 사용하는 변수나 함수가 아니고, 직접적으로 class를 통해서 변수와 함수를 사용하는 방식이다. 여기서 특이한점은,
static name이라고하고, static name이라고 하는 변수에 이 클래스의 이름은 C가 아니라 라고 적어주면,
위의 class A에서는 그 클래스는 무엇이냐? 라고했을때 그 클래스 이름이 나왔는데,
class C의 결과 값을 보게되면, static의 name 변수에 할당한 값이 C자리에 대신 들어와있는것을 확인할 수있다. 예) A클래스 : [class A] C클래스 : [class 이 클래스의 이름은 C가 아니다.] //이를보아 A처럼 C가 들어와야 될것같은데, 할당된 값이 나온것을 보면, static name이라는 변수가 class의 이름을 뜻한다는 것을 알 수 있게되었다.
상속(extends) class상속의 기본 - 이미 만들어져있는 class를 활용하는 방법 중에 하나인 상속.
오버라이드(override) - 클래스의 상속 멤버 변수 및 함수 오버라이딩, 추가 >상속을 활용할때 중요한 요소중에 하나이다. >부모에서 구현된 함수나 변수가 자식에게서 똑같이 같은이름으로 구현을 시키면 그것을 override 된다고한다. 즉, 자식이 만들어 놓은 함수가 부모의 함수를 덮어씌우는 결과를 가지고 오게 된다.
super -클래스의 상속 생성자 함수 변경 >super라는 키워드를 활용하여 자식이 생성자(constructor)에서 뭔가 추가하고자할때 supper을 꼭 호출해야된다는 사실을확인해보자