[JS] Class
1. Class 개요
1.1 Class 도입 배경
지금까지 객체 리터럴, 생성자함수를 사용하여 객체를 생성하는 방법을 배웠다.
- 객체 리터럴은 단일 객체를 생성하기 때문에 비슷한 객체를 여러개 만들어야 해 번거롭다.
- 생성자 함수는 생성자 함수를 상속할 때 프로토타입 체인을 조작해야 하기 때문에 복잡하다.
→ 따라서 ES6부터 생성자 함수를 좀 더 편하게 쓸 수 있도록 클래스 문법을 도입했다.
1.2 Class 개념
클래스와 객체
-
붕어빵에 비유하자면 클래스는 붕어빵 틀, 객체는 붕어빵 틀에서 생성된 붕어빵, 각각의 붕어빵을 인스턴스라고 할 수 있다.
-
클래스는 객체를 만들기 위한 설계도라고 생각할 수 있고, 이 설계도를 바탕으로 만들어진 실제 객체들은 인스턴스라고 생각할 수 있다.
→ 즉, 클래스는 객체를 생성하기 위한 일종의 템플릿인 것이다!
2. Class 생성
2.1 Constructor 개념
Constructor는 Class의 생성자 함수이다.
생성자 함수는 객체를 생성할 때 호출되며, 객체를 초기화하는 역할을 한다.
아래 코드에서 constructor
메소드는 name과 age를 인자로 받아 this.name과 this.age 속성을 초기화한다.
class Person {
// constructor 키워드를 사용하여 정의한다.
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(
`Hello, my name is ${this.name} and I'm ${this.age} years old.`
);
}
}
const person = new Person("Alice", 20);
2.2 Class 생성 예제
class를 생성하기 위해서는 class 키워드를 사용한다.
class Person {
// (1) 클래스(설계도) 생성
// Person을 생성하는 것이기 때문에,
// age를 필수 요소로 넣어주자.
constructor(name, age) {
// (2) constructor(생성자 함수)로 인스턴스 초기화
// 여기서 말하는 this는 만들어질 인스턴스(만들고자 하는 실체)를 의미한다.
this.name = name;
this.age = age;
}
// (3) 메서드 생성
sayHello() {
console.log(
`안녕하세요, 제 이름은 ${this.name}이고, 나이는 ${this.age}입니다.`
);
}
}
// (4) 인스턴스(실제 사물) 생성
const person1 = new Person("sieun", 22);
const person2 = new Person("kori", 8);
// (5) 만든 객체를 토대로 메서드 호출하기
person1.sayHello(); // "안녕하세요, 제 이름은 sieun이고, 나이는 22입니다."
person2.sayHello(); // "안녕하세요, 제 이름은 kori이고, 나이는 8입니다."
2.3 Class 생성 연습
문제
-
Car라는 새로운 클래스를 만들되, 처음 객체를 만들 때는 다음 네 개의 값이 필수로 입력돼야한다.
modelName
,modelYear
,type
,price
makeNoise()
메서드를 만들어 클락션을 출력해보자.
class Car {
constructor(modelName, modelYear, type, price) {
this.modelName = modelName;
this.modelYear = modelYear;
this.type = type;
this.price = price;
}
makeNoise() {
console.log(`${this.modelName}가 클락션을 울리네요. 빵빵!`);
}
}
const car1 = new Car("티코", "2002", "e", 5000);
const car2 = new Car("벤츠", "2024", "g", 3000);
const car3 = new Car("율무차", "2022", "t", 4500);
car1.makeNoise(); // "티코가 클락션을 울리네요. 빵빵!"
car2.makeNoise(); // "벤츠가 클락션을 울리네요. 빵빵!"
car3.makeNoise(); // "율무차가 클락션을 울리네요. 빵빵!"
3. Getter와 Setter
3.1 Getter와 Setter 개념
Class에서는 getter와 setter를 사용하여 Class의 속성에 접근할 수 있다.
getter는 속성 값을 반환하는 메소드이며, setter는 속성 값을 설정하는 메소드이다.
예를 들어, new 키워드로 생성한 사람이란 인스턴스가 나이라는 속성을 가질때, Class에서는 getter와 setter을 사용하여 외부로부터 값이 들어왔을 때 내부적으로 검증 후 세팅이 가능하다.
this
로 접근하는 property에 underscore(_)
를 사용해야해야 무한루프에 빠지지 않는다는 것을 기억하자!
3.2 Getter와 Setter 예제
// Getters와 Setters
// 객체지향 프로그래밍 언어 -> G, S
// 클래스 --> 객체(인스턴스)
// 프로퍼티(constructor)
// new Class(a, b, c)
class Rectangle {
constructor(height, width) {
// underscore : private(은밀하고, 감춰야 할 때)
this._height = height;
this._width = width;
}
// width를 위한 getter
get width() {
return this._width;
}
// width를 위한 setter
set width(value) {
// 검증 1 : value가 음수이면 오류!
if (value <= 0) {
//
console.log("[오류] 가로길이는 0보다 커야 합니다!");
return;
} else if (typeof value !== "number") {
console.log("[오류] 가로길이로 입력된 값이 숫자타입이 아닙니다!");
return;
}
this._width = value;
}
// height를 위한 getter
get height() {
return this._height;
}
// height를 위한 setter
set height(value) {
// 검증 1 : value가 음수이면 오류!
if (value <= 0) {
//
console.log("[오류] 세로길이는 0보다 커야 합니다!");
return;
} else if (typeof value !== "number") {
console.log("[오류] 세로길이로 입력된 값이 숫자타입이 아닙니다!");
return;
}
this._height = value;
}
// getArea : 가로 * 세로 => 넓이
getArea() {
const a = this._width * this._height;
console.log(`넓이는 => ${a}입니다.`);
}
}
// instance 생성
const rect1 = new Rectangle(10, 7);
rect1.getArea();
// const rect2 = new Rectangle(10, 30);
// const rect3 = new Rectangle(15, 20);
3.3 Getter와 Setter 연습
문제
- Getter와 Setter을 목차 2.3 Class 생성 연습에서 작성한 Car class에 적용해보자
modelName
,modelYear
,price
를 가져오는 메서드getModelName
,getModelYear
,getPrice
를 작성하자.- 그리고 가격변동이 일어났을 때 사용할 수 있는 메서드인
setPrice
도 작성하자
class Car {
constructor(modelName, modelYear, type, price) {
this._modelName = modelName;
this._modelYear = modelYear;
this._type = type;
this._price = price;
}
get modelName() {
return this._modelName;
}
// set은 입력값에 대한 검증까지 가능하다.
set modelName(value) {
// 유효성 검사
if (value.length <= 0) {
console.log("[오류] 모델명이 입력되지 않았습니다. 확인해주세요!");
return;
} else if (typeof value !== "string") {
console.log("[오류] 입력된 모델명이 문자형이 아닙니다!");
return;
}
// 검증이 완료된 경우에만 setting
this._modelName = value;
}
get modelYear() {
return this._modelYear;
}
set modelYear(value) {
// 유효성 검사
if (value.length !== 4) {
console.log("[오류] 입력된 년도가 4자리가 아닙니다.확인해주세요!");
return;
} else if (typeof value !== "string") {
console.log("[오류] 입력된 모델명이 문자형이 아닙니다!");
return;
}
// 검증이 완료된 경우에만 setting
this._modelYear = value;
}
get type() {
return this._type;
}
set type(value) {
if (value.length <= 0) {
console.log("[오류] 타입이 입력되지 않았습니다. 확인해주세요!");
return;
} else if (value !== "g" && value !== "d" && value !== "e") {
// 유효성 검사
// g(가솔린), d(디젤), e(전기차)가 아닌 경우 오류
console.log("[오류] 입력된 타입이 잘못되었습니다. 확인해주세요!");
return;
}
// 검증 완료!
this._type = value;
}
get price() {
return this._price;
}
set price(value) {
if (typeof value !== "number") {
console.log("[오류] 가격으로 입력된 값이 숫자가 아닙니다. 확인해주세요!");
return;
} else if (value < "1000000") {
console.log("[오류] 가격은 100만원보다 작을 수 없습니다. 확인해주세요!");
return;
}
// 검증이 완료된 경우에만 setting
this._price = value;
}
// 해당 자동차가 몇년도 모델인지 출력하는 메서드 작성
printModelYear() {
console.log(
this._modelName + "은 " + this._modelYear + "년도의 모델입니다."
);
}
}
// 자동차 만들기
const car1 = new Car("티코", "2002", "e", 5000);
const car2 = new Car("벤츠", "2024", "g", 3000);
const car3 = new Car("율무차", "2022", "t", 4500);
// 출력
car1.modelName = 1; // "[오류] 입력된 모델명이 문자형이 아닙니다!"
// getter 예시
console.log(car1.modelName); // "티코"
console.log(car3.type); // "t"
// setter 예시
car1.modelName = 1; // "[오류] 입력된 모델명이 문자형이 아닙니다!"
car3.type = "t"; // "[오류] 입력된 타입이 잘못되었습니다. 확인해주세요!"
4. 상속 (Inheritance)
4.1 상속 개념
Class는 상속을 통해 다른 Class의 기능을 물려받을 수 있다.
상속을 받는 Class를 subclass
또는 derived class
라고 하며, 상속을 하는 Class를 superclass
또는 base class
라고 한다. (부모-자식)
4.2 상속 예제
class Animal {
// 생성자 (이름을 필수로 받아야 한다.)
constructor(name) {
this.name = name;
}
// 메서드 (동물 행동 정의)
speak() {
console.log(`${this.name} makes a noise.`);
}
}
// 동물 클래스를 상속받는 Dog 클래스를 생성
class Dog extends Animal {
// 부모에게서 내려받은 메서드를 재정의
speak() {
console.log(`${this.name} 멍멍!`);
}
}
// Dog를 만들 때는 Animal의 상속을 받은 class이기 때문에 이름을 필수로 받아야 한다.
let cuttyPuppy = new Dog("코리");
// speak는 "makes a noise"가 아니라, "멍멍!"이 출력된다.
cuttyPuppy.speak(); // "코리 멍멍!"
부모로부터 내려받아 재정의 하는 것을 오버라이딩이라고 한다.
위 코드에서 Dog Class는 Animal Class를 상속받았다. Dog Class에서 speak 메소드를 오버라이딩하여 Animal Class의 speak 메서드를 덮어쓴 것이다.
4.3 상속 연습
문제
- 상속을 목차 2.3 Class 생성 연습에서 작성한 Car class에 적용해보자.
- Car 클래스로부터 상속받아 전기자동차 클래스를 만들어보자.
- 전기차이기 때문에 constructor 상에 type은 필요 없을 것이다. 따라서 재정의가 필요하기 때문에 constructor을 사용해야한다.
class Car {
constructor(modelName, modelYear, type, price) {
this.modelName = modelName;
this.modelYear = modelYear;
this.type = type;
this.price = price;
}
makeNoise() {
console.log(`${this.modelName}가 클락션을 울리네요. 빵빵!`);
}
}
// 전기차 class 정의 (상속)
class ElectronicCar extends Car {
// constuctor로 재정의
constructor(modelName, modelYear, price) {
// Car(부모 class)에게도 재정의 한 사항 알려주기
super(modelName, modelYear, "e", price);
}
}
const eleCar1 = new ElectronicCar("테슬라", "2022", 10000);
eleCar1.makeNoise(); // "테슬라가 클락션을 울리네요. 빵빵!"
문제
- 작성한 코드를 토대로 전기자동차의 특성을 고려해서 충전시간도 추가해보자
class Car {
constructor(modelName, modelYear, type, price) {
this.modelName = modelName;
this.modelYear = modelYear;
this.type = type;
this.price = price;
}
makeNoise() {
console.log(`${this.modelName}가 클락션을 울리네요. 빵빵!`);
}
}
// 전기차 class 정의 (상속)
class ElectronicCar extends Car {
// constuctor로 재정의
constructor(modelName, modelYear, price, chargeTime) {
// Car(부모 class)에게도 재정의 한 사항 알려주기
super(modelName, modelYear, "e", price);
this._chargeTime = chargeTime;
}
set chargeTime(value) {
this._chargeTime = value;
}
get chargeTime() {
return this._chargeTime;
}
}
const eleCar1 = new ElectronicCar("테슬라", "2022", 10000, 60);
console.log(eleCar1._chargeTime); // 60
eleCar1.chargeTime = 20;
console.log(eleCar1._chargeTime); // 20
5. Static Method
Static Method는 인스턴스를 만들 필요가 없을 때 사용한다.
즉, 인스턴스 간에 복제할 필요가 없는 데이터 (똑같은 것을 공유해서 쓸 때)에 사용한다.
Class는 static
키워드를 사용하여 Class 레벨의 메소드를 정의할 수 있다.
Class 레벨의 메소드는 인스턴스에서 호출할 수 없으며, Class 이름으로 직접 호출할 수 있다.
class Calculator {
// constructor 생략 가능
// constructor(a, b) {
// this._a = a;
// this._b = b;
// }
static add(a, b) {
return a + b;
}
static subtract(a, b) {
return a - b;
}
}
console.log(Calculator.add(1, 2)); // 3
console.log(Calculator.subtract(3, 2)); // 1
댓글남기기