2차 공부/TIL

24.07.25 클래스

공대탈출 2024. 7. 25. 16:30

클래스와 인스턴스

클래스 - 학교에서 다양한 종류의 책상을 만드는 설계도, 설계도를 보면 어떤 종류의 책상을 만들 수 있는지, 책상의 특징은 무엇인지 알 수 있다.

인스턴스 - 설계도를 보고 만들어진 실제 책상, 모양/크기/색상/재료 등 설계도에 따라 만들어지며 모두 다른 인스턴스가 된다.

 

// 클래스라는 설계도를 만들어 봅시다.
class Person {
    //사람이기 때문에 필수요소를 name, age를 가진다.
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    //이렇게 함수를 만들어두면 인스턴스를 만들 때 메서드가 들어있다.
    sayHello() {
        console.log(`${this.name}님 안녕하세요!`);
    }

    //내 나이는 ~살이에요!라고 출력하는 메서드
    sayMyAge() {
        console.log(`내 나이는 ${this.age}살이에요!`);
    }
}

//설계도를 통해 실제 사물을 만들어보자.
//이름은 홍길동이고 나이는 30살인 사람을 설계도에 근거해서 만들어줘.
const person1 = new Person("홍길동", "30");
const person2 = new Person("홍길순", "25");
//어떤 배열을 탐색하며 클래스에 맞게 반복적으로 만들어 낼 수 있다.

//만들어둔 sayHello 메서드 사용
person1.sayHello();
person1.sayMyAge();
person2.sayHello();
person2.sayMyAge();

class와 constructor으로 설계도를 만들어 두고 new Person()으로 필수요소를 넣어주어 인스턴스를 생성한다.

class를 만들 때 함수를 넣어주면 해당 인스턴스의 메서드로 사용할 수도 있다.

 

class Car {
    constructor(modelName, modelYear, type, price) {
        this.modelName = modelName;
        this.modelYear = modelYear;
        this.type = type;
        this.price = price;
    }
    makeNoise() {
        console.log(`${this.modelName}: 빵!빵!`);
    }
    getModelYear() {
        console.log(
            `${this.modelName}은(는) ${this.modelYear}년에 생산되었습니다.`
        );
    }
}

let carA = new Car("a", 2024, "suv", "5000만원");
let carB = new Car("b", 2000, "sedan", "3000만원");
let carC = new Car("c", 2010, "truck", "12000만원");

carA.makeNoise();
carB.makeNoise();
carC.makeNoise();

carA.getModelYear();
carB.getModelYear();
carC.getModelYear();

// Getters 와 Setters
// 객체지향 프로그래밍 언어 > Getters, Setters가 있다.
// 클래스 -> 객체(인스턴스)
// 프로퍼티(constructor)
// new Class(a, b, c)

class Rectangle {
    constructor(height, width) {
        // underscore : private(은밀하고 감춰야 할 때)
        this._height = height;
        this._width = width;
    }

    get width() {
        return this._width;
    }
    set width(value) {
        //검증1: value가 음수이면 오류
        if (value < 0) {
            console.log("[오류] 가로길이는 0보다 커야 합니다.");
            return;
        } else if (typeof value !== "number") {
            console.log("[오류] 가로길이로 입력된 값이 숫자타입이 아닙니다.");
            return;
        }

        this._width = value;
    }
    get height() {
        return this._height;
    }
    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}입니다.`);
    }
}

//인스턴스 생성
let rect1 = new Rectangle(10, 20);
rect1.getArea();
// let rect2 = new Rectangle(10, 30);
// let rect3 = new Rectangle(15, 20);

set의 height와 이름이 같아 무한루프에 빠지지않도록 this._height로 이름을 정해야한다. _는 일종의 컨벤션이다.

 

이렇게 getter와 setter을 만들어 위에서 작성한 class Car을 바꿔보자.

// 클래스 연습해보기!
// [요구사항]
// 1. Car라는 새로운 클래스를 만들되, 처음 객체를 만들 때는
//    다음 네 개의 값이 필수로 입력돼야 합니다!
//    (1) modelName
//    (2) modelYear
//    (3) type : 가솔린, 전기차, 디젤
//    (4) price
// 2. makeNoise() 메서드를 만들어 클락션을 출력해주세요.
// 2-1. 해당 자동차가 몇년도 모델인지 출력하는 메서드 작성!
// 3. 이후 자동차를 3개 정도 만들어주세요(객체 생성)

// [추가 요구사항]
// 1. modelName, modelYear, price, type을 가져오는 메서드
// 2. modelName, modelYear, price, type을 세팅하는 메서드
// 3. 만든 인스턴스를 통해서 마지막에 set 해서 get 하는 로직까지
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 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;
        }

        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;
        }
        this._price = value;
    }

    // 클락션을 울리는 메서드
    makeNoise() {
        console.log(this._modelName + ": 빵!");
    }

    // 해당 자동차가 몇년도 모델인지 출력하는 메서드 작성!
    printModelYear() {
        console.log(
            this._modelName + "은 " + this._modelYear + "년도의 모델입니다."
        );
    }
}

// 자동차 만들기
const car1 = new Car("Sorento", "2023", "e", 5000);
const car2 = new Car("SM5", "1999", "g", 3000);
const car3 = new Car("Palisade", "2010", "d", 4500);
// car1.makeNoise();
// car1.printModelYear();
// car2.makeNoise();
// car2.printModelYear();
// car3.makeNoise();
// car3.printModelYear();

// getter 예시1
console.log(car1.modelName);	//Sorento
// setter 예시1
car1.modelName = 1;	//[오류] 입력된 모델명이 문자형이 아닙니다!
console.log(car1.modelName);	//Sorento

// 상속(Inheritance)
// Class -> 유산으로 내려주는 주요 기능!
// 부모 <-> 자식

// 동물 전체에 대한 클래스
class Animal {
    constructor(name) {
        this.name = name;
    }

    //짖다
    speak() {
        console.log(`${this.name} says!`);
    }
}

const me = new Animal("sg");
me.speak();

// Dog Class는 Animal을 상속받는다.
class Dog extends Animal {
    //부모에게서 내려받은 메서드를 재정의 할 수 있음
    //overriding...
    speak() {
        console.log(`${this.name} barks!`);
    }
}

const cutyPuppy01 = new Dog("강아지");
cutyPuppy01.speak();

부모 Animal class에서 constructor을 내려받아 재정의하지 않아도 된다.

speak()도 똑같이 내려받는데, 다시 정의하여 바꿀 수 있다.

 

위에서 작성했던 Car class를 상속하는 electronicCar class를 만들었다.

//Car class를 상속받는 전기차 클래스를 만들어라.
class Car {
    constructor(modelName, modelYear, type, price) {
        this.modelName = modelName;
        this.modelYear = modelYear;
        this.type = type;
        this.price = price;
    }
    makeNoise() {
        console.log(`${this.modelName}: 빵!빵!`);
    }
    getModelYear() {
        console.log(
            `${this.modelName}은(는) ${this.modelYear}년에 생산되었습니다.`
        );
    }
}

//전기차 class
class ElectronicCar extends Car {
    //기본적으로 상속받을때는 constructor가 필요없지만
    //재정의가 필요할 때에는 재정의를 해야한다.
    //여기선 type이 항상 'e'이므로
    constructor(modelName, modelYear, price, chargeTime) {
        //Car에게도 알려주기!
        super(modelName, modelYear, "e", price);
        this._chargeTime = chargeTime;
    }
    get chargeTime() {
        return this._chargeTime;
    }
    set chargeTime(value) {
        this._chargeTime = value;
    }
}

const eleCar1 = new ElectronicCar("tesla", "2020", 9000, 60);
eleCar1.makeNoise();
eleCar1.getModelYear();
console.log("----------------");
console.log(eleCar1._chargeTime);
eleCar1.chargeTime = 20;
console.log(eleCar1._chargeTime);

기본적으로 Car class를 상속받지만, type은 'e'로 고정되어있으며, 메소드들을 상속받기도 하고, 전기차의 특성인 충전시간을 ElectronicCar class에만 추가하여 설정해주었다.

자식 class에서 새롭게 재정의해야하는 것이 있다면, 부모 class에서 super을 통해 알려주고나서 this에 새로운 값을 추가해야만 추가가 가능하다.

 


class의 정적 메소드

우리가 계산을 해주는 class를 만든다고 생각해보자

그렇다면 굳이 숫자를 받아와서 constructor에서 두 값을 this에 넣어주고

add(){} 메서드에서 this.a를 어쩌구저쩌구 할 필요없이

그냥 Calculator.add(3,5)하면 8이 나오도록 하고싶다. 이때는 static을 메소드 앞에 붙여주면 된다.

// Static Method(= 정적 메소드)
// Class -> 객체를 만들기 위해서 사용한다.
// 다량으로, 안전하고, 정확하게
class Calculator {
    static add(a, b) {
        console.log(`[계산기] 더하기를 진행합니다.`);
        return a + b;
    }
    static substractor(a, b) {
        console.log(`[계산기] 빼기를 진행합니다.`);
        return a - b;
    }
}

console.log(Calculator.add(3, 5)); // 8
console.log(Calculator.substractor(3, 5)); //-2

 

'2차 공부 > TIL' 카테고리의 다른 글

24.07.26 영화검색페이지 리팩토링하기  (0) 2024.07.26
24.07.25 클로저  (0) 2024.07.25
24.07.25 DOM / DOM 조작하기  (0) 2024.07.25
24.07.24 콜백지옥 / 동기, 비동기  (0) 2024.07.24
24.07.23 This  (0) 2024.07.23