개발 일지 (TIL)

TIL 2023 08 22

늘곰's 2023. 8. 22. 21:38

오늘 배운것 

class

// 클래스 연습

// [요구사항] 
// Car 라는 새로운 클래스를 만들되, 처음 객체를 만들 때는
// 다음 네 개의 값이 필수로 입력돼야 합니다!

// 1. modelName
// 2. modelYear
// 3. type
// 4. price

// 2. makeNoise() 매서드를 만들어 클락션을 출력해주세요.
// 2-1 해당 자동차가 몇년도 모델인지 출력하는 매서드 작성!
// 3. 이후 자동차를 3개 정도 만들어주세요 ( 객체 생성)

// [추가 요구사항]
// 1. modelName ,modelYear , type ,price 을 가져오는 매서드
// 2. modelName ,modelYear , type ,price 을 세팅하는 매서드
class Car{
    constructor(modelName,modelYear,type,price){
        this.modelName = modelName;
        this.modelYear = modelYear;
        this.type = type;
        this.price = price;
    }
    // 클락션 울리는 매서드
    makenoise() {
    console.log(this.modelName + ': 빵!')
    }
    // 몇년도 모델인지
    PrintModelYear(){
        console.log(this.modelName + '은' +  this.modelYear + '년도의 모델입니다.')   
    }

    get modelName () {
        return this._modelName;
    }
    set modelName (value) {
        // 유효성 검사
        if(value.length <= 0){
            console.log('[오류] 모델명이 입력되지 않았습니다.')
            return;
        }else if (typeof value !== 'string'){
            console.log('[오류] 입력된 모델명이 문자가 아닙니다 확인해주세요!')
            return;
        }
        this._modelName = value;
    }

    get modelYear () {
        return this._modelYear;
    }
    set modelYear(value) {
        if(typeof value !== 'string'){
            // 년도에 대한 유효성 검증 로직 --> 구글링하면 많이 나옴
            console.log('[오류] 입력된 모델명이 문자가 아닙니다 확인해주세요!')
            return;
        }else if (value.length !== 4){
            console.log('[오류] 모델명이 입력되지 않았습니다.')
            return;
        }
        this._modelYear = value;
    }


    get type() {
        return this._type;
    }
    set type(value) {
        //g , d ,e 가솔린 디젤 전기차
        if(value !== 'g' && value !== 'd' && value !== 'e'){
            console.log('[오류] 입력된 타입이 잘못 되었습니다. 확인해주세요!')
            return;
        }else if (value.length <= 0){
            console.log('[오류] 타입이 입력되지 않았습니다.')
            return;
        }
        // 검증완료
        this._type = value;
    }


    get price() {
        return this._price;
    }
    
    set price(value) {
        //g , d ,e 가솔린 디젤 전기차
        if(typeof value !== 'number'){
            console.log('[오류] 숫자 아님')
            return;
        }else if (value.length <= '1000000'){
            console.log('[오류] 가격은 100만원보다 작을 수 없습니다.')
            return;
        }
        // 검증완료
        this._type = value;
    }

}



//자동차 만들기
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 예시
console.log(car1.modelName);
// setter 예시
car1.modelName ='kia'
console.log(car1.modelYear);

class 의 상속

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

// 동물 전체에 대한 클래스

class Animal {
    //생성자
    constructor (name) {
        this._name = name;
    }


//매서드

speak () {
    console.log(`${this._name} says!`)
}

}

// extends 어떤클래스의 상속을 받을것인가?

class Dog extends Animal{
    // 부모에게서 내려받은 매서드를 재정의 할 수 있음
    // overriding 상속 매서드를 내려받아 재정의하는것  /오버라이딩
    speak(){
        console.log(`${this._name} wak!`)
        
    }
}

const cuttyPuppy01 = new Dog('레오');

cuttyPuppy01.speak();

static Method (정적 메소드)

간단한 내용들은 class 를 만들 필요 없이 static 을 사용 할 수 있다. 

// static Method (=정적 메소드)
// Class -> 객체를 만들기 위해서 사용
// 다량으로, 안전하고 , 정확하게

class Calculator {
    
   static add (a,b){
    console.log('더하기를 진행합니다')
    return a + b;
    }
static substract(a,b){
    console.log('빼기를 진행합니다')
    return a - b;
}

}
console.log(Calculator.add(3,5))
console.log(Calculator.substract(3,5))

 

함수를 사용시 많이 실수하는 부분

 

// [렉시컬 스코프]
// js 엔진은 함수를 어디서 '호출'했는지가 아니라
// 어디에 '정의' 했는지에 따라서 스코프(상위스코프)를 결정


//외부 렉시컬 환경에 대한 참조값 => outer
// 함수 정의가 평가되는 시점 !!!
 
const x =1;

function outerFunc () {
    // 아우터 펑크내에 이너 펑크가 
    // '호출' 되고 있음에도 불구하고
    const x =10;
    innerFunc();  // 1
}
// 이너 펑크와 아우터 펑크는 서로 다른 스코프를 가지고 있다.
function innerFunc(){
    console.log(x);  // 1
}

outerFunc();

closure

// closure 클로저
// 상태를 안전하게 변경하고 유지하기위해

// 카운트 상태 변경 함수 #1
// 함수가 호출될 때마다 호출된 횟수를 누적하여 출력하는 카운터를 구현해요!

// 카운트 상태 변수
let num = 0;

// 카운트 상태 변경 함수
const increase = function () {
    // 카운트 상태를 1만큼 증가시킨다.
    return ++num;
};

console.log(increase());
// num = 100; // 치명적인 단점이 있어요.
console.log(increase());
console.log(increase());


// 보완사항
// 1. 카운트 상태 num 변수의 값 => increase 함수가 호출되기 전에는 변하면 안됨
// 2 .이를 위해서 count상태는 increase 함수만 변경할수 있어야 한다.
// 3. 전역변수 num 요놈이 문제 ... 그럼 지역변수로 바꾸면?

이것을 지역변수로 바꾸면 함수를 실행할때 마다 변수가 초기화 되어버려서 값이 1 밖에 나오지 않게된다.

문제 해결법

// 카운트 상태 변경 함수 #3
const increase = (function () {
    // 카운트 상태 변수
    let num = 0;
  
    // 클로저
    return function () {
      return ++num;
    };
  })();
  
  // 이전 상태값을 유지
  console.log(increase()); //1
  console.log(increase()); //2
  console.log(increase()); //3

  // 코드설명
  // 1. 이 코드가 실행되면 , '즉시 실행 함수' 가 호출 -> 함수가 반환 inner -> increase
  // 2. increase 에 할당된 함수는 자신이 정의된 위치에 의해서 결정된 상위스코프인
  // 즉시 실행 함수의 ' 렉시컬 환경' 을 기억하는 
  // 클로저 --> let num =0;을 기억한다
  // 3. 즉시 실행함수는 -> 즉시 소멸된다 (outer 함수가 불리자마자 바로 call stack 에서 popup되는 것과 비슷)
  // 결론 : num은 초기화가 x 외부에서 접근할 수 없는 은닉된 값!!!