[Node.js_4기] Today_I_Learn : JS (24/01/04)

2024. 1. 4. 21:20공부/내배캠 TIL

목차

 

1. 학습 내용

2. 내용 정리

3. 예제

4. 생각 정리

 

1. 학습 내용 

 

1. DOM의 기본 개념과 접근, 제어법

2. Class문법의 주요 개념(클래스, 인스턴스, getter, setter, 상속 등)

3. 클로저의 주 개념과 활용

 

2. 내용 정리 

1. DOM

(3) DOM(Document Object Modeling)

브라우저 내장 API(다른 시스템에 제공하는 기능의 사용을 도와주는 중간자) - HTML을 Js로 접근, 제어가 가능하다.

DOM의 모든 node는 속성과 메서드를 가지고 있다.(Node : html태그와 텍스트, 속성등을 하나의 블록처럼 취급)

속성 : 해당 객체의 특성을 나타내는 값을 가져오거나 설정

메서드 : 해당 객체가 수행하는 작업을 나타내는 함

 

2. Class

클래스 : 다양한 종류의 객체를 만드는 설계도. / 인스턴스 : 설계도로 만들어진 객체

(1) class : 객체를 생성하기 위한 템플릿

(2) constructor : class 생성자 함수. 객체를 초기화.

(3) getter, setter : class의 속성에 접근. getter = 속성값 반환 메소드, setter = 속성값 설정 메소드

(4) inheritance : 다른 class의 기능을 물려받음. 오버라이딩을 통한 메소드 덮어씌움 등.

(5) static method : class레벨의 메소드 정의. 인스턴스를 만들지 않고 사용할 수 있음.

 

3. Closer

(1) 클로저 : 함수와 그 함수가 선언된 렉시컬 환경과의 조합! -> 뭔 개소리지...

1. 렉시컬 스코프 :

a. js에서 함수의 상위 스코프는 함수를 어디에 정의했는지에 따라 결정된다.

b. 외부 렉시컬 환경 참조(스코프에 대한 참조)는 함수가 정의된 환경(위치)에 의해 결정. 이것이 렉시컬 스코프.

 

3. 예제 

<1. DOM>

document.getElementById("demo").innerHTML = "Hello World!";
// getElementById() = 메서드
// innerHTML = 속성

<2. Class>

// (1) 클래스 기본
// 클래스 생성
// [요구사항]
// 1. car라는 새로운 클래스
// -1 modelName
// -2 modelYear
// -3 type
// -4 price
// 2. makeNoise() 클락션 출력
// 3. 인스턴스 생성
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('car1','20230101','e', 11111)
car1.makeNoise();
// ========================================================
// (2) Getters, Setters
// [추가 요구사항]
// 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;
    }
    // 입력값에 대한 검증까지 가능하다 -> gettet/setter을 쓰는 가장 큰 이유
    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) {
            // 연도에 대한 유효성 검증 로직 ---> googling 엄청~~~~많이 나옵니다!!
            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;
        }

        // 검증이 완료된 경우
        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);

// getter 예시1
console.log(car1.modelName);
// setter 예시1
car1.type = 'super'
console.log(car1.modelName);
// ===================================================
// (3) 상속
// [추가 요구사항]
// 1. 전기차 클래스 <- Car클래스 상속받을거임.
class ElectronicCar extends Car{
    constructor(modelName, modelYear, price, chargeTime){
        // 부모 클래스에게도 알려줘볼까?
        super(modelName, modelYear, 'e', price);
        this._chargeTime=chargeTime;
    }

    set chargeTime(value){
        this._chargeTime=value;
    }
    get chargeTime(){
        return this._chargeTime;
    }

}

const eCar1 = new ElectronicCar('cybertruck','2023',9000,60)
eCar1.makeNoise();
console.log('-----------------');
console.log(eCar1._chargeTime);
eCar1.chargeTime = 20;
console.log(eCar1.chargeTime);
// ===========================================================
// (4) 정적 메서드
// static method(=정적 메소드)
// class -> 객체 생성
// 다량, 안전, 정확
// 굳이 인스턴스화 시킬 필요 없을 때 사용.
class Calculator{
    static add(a,b){
        console.log('[clac] add them');
        return a+b;
    }

    static sub(a,b){
        console.log('[calc] sub them');
        return a-b
    }
}

console.log(Calculator.add(3,5));
console.log(Calculator.sub(4,2));

<3. 클로저>

// 카운트 상태 변경 함수 # 1
// 함수가 호출될 떄마다 호출된 횟수를 누적하는 카운터 구현
let num = 0;
const increase = function(){
    return ++num;
};
console.log(increase());
num=100;
console.log(increase());
console.log(increase());
// 리뷰
// 1. 카운트 상태 -> increase호출 전까지 num 변경 x
// 2. count 상태를 increase만이 변경할 수 있게.
// 3. 전역변수 num <- 누구나 접근해서 변경 가능
// ===============================================================
// 카운트 상태 변경 함수 # 2
const increase = function(){
    let num = 0;
    return ++num;
};

// 이전 상태 유지를 못한다...
console.log(increase());
num=100;
console.log(increase());
console.log(increase());

// 리뷰
// 1. num변수를 지역변수로 넣었다. -> 변경은 방지
//  = num변수를 increase만이 변경할 수 있었다.
// 2. 근데 호출 마다 초기화되는 코드.(몇번 호출해도 출력이 1)
// -> 의도치 않은 변경은 방지 + 이전 상태를 유지하게...
// -> ★클로저로 구현한다★
// ==================================================================
const increase = (function(){
    // 카운트 상태 변수
    let num = 0;

    // 클로저
    return function(){ // increase = 항상 외부 환경 참조중
        return ++num;
    };
})();

// 이전 상태 유지를 못한다...
console.log(increase());
num=100;
console.log(increase());
console.log(increase());

// 코드 리뷰
// 1. 코드 실행시, 즉시 실행 함수 호출 -> 함수가 반환
// -> increase에 할당
// 2. increase에 할당된 함수는 위치에 의해 결정된 상위 스코프의
// 즉시 실행 함수의 렉시컬 환경을 기억하는 클로저
// -> let num = 0;을 기억한다.
// 3. 즉시 실행함수 -> 즉시 소멸
// outer함수가 불리자마자 call stack에서 pop up 됨과 같음.
// 결론 : num 초기화 x, 의도되지 않는 변경 x(increase시에만 변경)

 

4. 생각 정리 

 

class의 경우, 파이썬 class 선언과 비슷한 방식으로 진행되어 이해가 쉬웠다. 

클로저 부분은 설명을 다시 들어도 아직 이해가 안되고 있다.