class
라는 키워드를 사용.멤버변수
의미 : 클래스에 만드는(포장하는) 함수
별칭 : 멤버함수
주로 객체 프로퍼티 값 변경 및 탐색, 클래스 대표 기능 등이 담김
사용법
클래스명.메소드명()
저장 위치
해당 클래스의 프로토타입 ( ↔ 생성자 함수의 저장 위치: 객체 내부 )
- 객체를 만들어주는 생성자 메서드
- 인스턴스가 만들어지면서 자동으로 호출되는 함수
class
내부new
를 통해 호출 시, 자동 실행.// 👉 생성자 함수
const User = function(name, age){
this.name = name;
this.age = age;
this.showName = function(){
console.log(this.name)
}
}
const mike = new User('mike',30)
// 👉 class
class User2 {
constructor(name, age){
this.name = name; // 이렇게 하면 객체에 name, age가 만들어짐
this.age = age;
}
showName () {
console.log(this.name)
}
}
const tom = new User2('tom', 19)
new
를 통해서 호출 시, 내부에서 정의된 내용으로 객체 생성mike
// User {name: 'mike', age: 30, showName: ƒ}
tom
// User2 {name: 'tom', age: 19}
// 동일
mike.showName() // mike
tom.showName() // tom
const User = function(name, age){
this.name = name;
this.age = age; // 👈 showName() 제거
}
User.prototype.showName = function(){ // 👈 showName() 추가
console.log(this.name)
}
const mike = new User('mike',30)
확인
같음. 생성자 함수로도 구현 가능
class
가 단순히 문법의 편의성을 위해 탄생 x
class
: 가능 (new
없이 호출 시 에러가 발생되도록 설계)- 생성자 함수: 불가 (잘 동작)
생성자 함수: 클래스처럼 동작하도록 제작
new
제거
// 👉 생성자 함수
const User = function(name, age){
this.name = name;
this.age = age;
}
User.prototype.showName = function(){
console.log(this.name)
}
const mike = User('mike', 30) // new 제거
// 👉 class
class User2 {
constructor(name, age){
this.name = name;
this.age = age;
}
showName () {
console.log(this.name)
}
}
const tom = User2('tom', 19) // new 제거
확인
mike
/*
- 결과: undefined
- 설명: 문제 없음. User함수가 return문이 없기 때문에 반환 x -> undefined가 됨. 그 값이 mike로 들어옴.
- 문제: 실수한 코드이지만 잘 동작. -> 에러 즉시 알아 수 없음. */
tom
/*
- 결과: TypeError 발생.
- 에러 메세지: TypeError: Class constructor User2 cannot be invoked without 'new'(class는 new 없이 실행할 수 없다.)*/
new
를 다시 넣고 콘솔창 비교
class
(User2
)의 constructor
(프로토타입 내부): class
명시.
→ constructor
가 class
인 것 파악 가능 & 이 경우, new
없이 호출 시 에러가 발생되도록 설계됨.
class
: 객체가 가지고 있는 프로퍼티만 보임- 생성자 함수: 프로토타입에 포함된 프로퍼티들을 다 보여줌.
(객체가 가지고 있는 프로퍼티 판별 방법:hasOwnProperty
사용)
// ✅ 생성자 함수
for (const p in mike) {
console.log(p)
}
/*
- 결과:
name
age
showName
- 설명: 다 나옴(프로토타입에 있는 것 까지)
*/
// ✅ class
for(const p in tom){
console.log(p)
}
/*
- 결과:
name
age */
클래스: extends
사용
생성자 함수: 프로토타입 이용
class Car {
constructor(color){
this.color = color;
this.wheels = 4;
}
drive(){
console.log('drive...')
}
stop(){
console.log('STOP!')
}
}
class Bmw extends Car {
park(){
console.log('park')
}
}
const z4 = new Bmw('blue')
z4
확인
Car
클래스에서 선언한 color
, wheels
가 들어있음
1번째 프로토타입
park
(class
내부에서 선언한 메소드 위치: 프로토 타입 밑)
2번째 프로토 타입
drive
, stop
z4.drive()
실행
결과
'drive...’
과정
z4
객체에서 찾음. → 없음.drive()
실행
오버라이딩
이란?
- JS 객체의 상속받은 부모의 메소드 재정의
super.메소드명
으로 부모 클래스에 정의된 메소드를 사용하는 방식
부모 & 자식 클래스의 메소드명이 서로 같다면 → 덮어쓰게 됨.
부모의 메소드를 사용 & 확장하고 싶다면 super
(super.메소드명
) 사용
예시
부모(
Car
) & 자식(Bmw
) 클래스 간 동일한 이름의 메소드 존재
class Car {
constructor(color){
this.color = color;
this.wheels = 4;
}
drive(){
console.log('drive...')
}
stop(){ // 👈 동일
console.log('STOP!')
}
}
class Bmw extends Car {
park(){
console.log('park')
}
stop(){ // 👈 동일
console.log('OFF')
}
}
const z4 = new Bmw('blue')
z4.stop() // 'OFF' 👈 덮어 쓰게 됨.
오버라이딩 활용
class Car {
(...생략)
stop(){
console.log('STOP!')
}
}
class Bmw extends Car {
(...생략)
stop(){
super.stop(); // 👈 Car의 stop() 사용
console.log('OFF')
}
}
const z4 = new Bmw('blue')
z4.stop()
/*
- 결과:
STOP! 👈 부모 클래스(Car)의 메소드(stop()) 먼저 실행
OFF */
- 자식 생성자는 무조건 부모 생성자를 호출해야 됨.
constructor
에서this
사용 전, 부모 생성자(super constructor
) 선 호출 필수- 자식
class
의constructor
에도 동일한 인수를 받는 작업 필요
class
의 constructor
는 빈 객체 ({}
)를 만들어주고 this
로 이 객체를 가리키는 작업을 함.
반면 extends
를 써서 만드는 자식 class
는 위 작업을 건너뜀.
→ 그래서 항상 super()
키워드로 부모 class
의 constructor
를 실행해야 함.
문제
class Car {
constructor(color){
this.color = color;
this.wheels = 4;
}
drive(){
console.log('drive..')
}
stop(){
console.log('STOP!')
}
}
class Bmw extends Car {
constructor(){
this.navigation = 1; // 👈[에러 발생 원인] 부모 생성자(super constructor) 無
}
park(){
console.log('PARK')
}
}
const z4 = new Bmw('blue')
해결 1 | 부모 생성자 선호출
class Car {
constructor(color){ // {} 👈 빈 객체
this.color = color;
this.wheels = 4;
}
(...생략)
}
class Bmw extends Car {
constructor(){
super(); // 👈 부모 class의 constructor 실행
this.navigation = 1;
}
(...생략)
}
const z4 = new Bmw('blue')
// 확인
z4
/*
- 결과:
Bmw {color: undefined, wheels: 4, navigation: 1}
color: undefined
navigation: 1
wheels: 4
[[Prototype]]: Car
- 해석:
color는 undefined.(생성 시, 'blue'넣었음에도 불구)
navigation는 잘 들어옴.
- 해결 방법:
제대로 동작하기 위해서는 자식 class의 constructor에 동일한
인수를 받는 작업을 해야 함. */
해결 2 | 자식 class
의 constructor
에 동일 인수 넘김
(...생략)
class Bmw extends Car {
constructor(color){ // 👈 color 받아 넘김
super(color); // 👈
this.navigation = 1;
}
(...생략)
}
(...생략)
// 확인
z4
/*
- 결과:
Bmw {color: 'blue', wheels: 4, navigation: 1}
color: "blue"
navigation: 1
wheels: 4
[[Prototype]]: Car
- 해석:
color: 'blue'까지 잘 나옴.
*/
자식 class
에 constructor
가 없을 경우
자식 생성자는 무조건 부모 생성자를 호출
class Car {
constructor(color){
this.color = color;
this.wheels = 4;
}
(<...생략)
}
class Bmw extends Car {
constructor(...args){ // 👈 constructor가 없으면 이 부분이 있는 것처럼 행동.
super(...args);
}
(...생략)
}
const z4 = new Bmw('blue')
자식 class
에 constructor
가 있을 경우
없을 경우처럼 처리되지 않음.
→ 항상 super
를 이용해 호출 & this.property
로 할당 필요
class Car {
constructor(color){ // 3. 이 작업 제대로 실행 가능.
this.color = color;
this.wheels = 4;
}
(...생략)
}
class Bmw extends Car {
constructor(){ // 1. color 값을 여기서 받은 다음
super(); // 2. 이쪽으로 넘겨줘야
}
(...생략)
}
const z4 = new Bmw('blue')
참고