본 캠프/JavaScript 문법 종합반

JavaScript 문법 종합반 2주차. (2)

Iruka913 2024. 10. 15. 20:47

클래스 찍어내기. 

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("sorento", '10', "e", 1000);
const car2 = new Car("sonata", '20', "g", 1000);
const car3 = new Car("sm5", '30', "d", 1000);

car1.makeNoise();
car2.makeNoise();
car3.makeNoise();

 

Car 라는 클래스를 만들어보았다. 클래스를 만들 때 필요한 건 컨스트럭터 함수라고 할 수 있겠다. 그리고, 컨스트럭터 함수 안에는 this에 변수로 받아온 인자를 묶어줄 필요가 있다. 

 

// getters와 setters

class rectangle {
    constructor(width, height) {
        this.width = width;
        this.height = height;
    }
}

// 새 인스턴스 생성
const rectangle1 = new rectangle(10, 20);
const rectangle2 = new rectangle(15, 20);
const rectangle3 = new rectangle(10, 30);

 

// getters와 setters

class rectangle {
    constructor(width, height) {
        this._width = width;
        this._height = height;
    }

    get width() {
        return this._width;
    }

    set width(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) {
        if (value <= 0) {
            console.log("세로 길이는 0보다 커야지");
            return;
        } else if (typeof value !== 'number') {
            console.log("숫자를 입력해주세요");
            return;
        }
        this._height = value;
    }

    getArea () {
        const a = this._width * this._height
        console.log(a)
    }
}

// 새 인스턴스 생성
const rectangle1 = new rectangle(10, 20);
rectangle1.getArea()

// const rectangle2 = new rectangle(15, 20);
// const rectangle3 = new rectangle(10, 30);

 

배운 것 1. 컨스트럭터에서 값을 할당할 때, this. 뒤에 언더바를 꼭 붙여주기. 

배운 것 2. 게터스와 세터스를 이용하면 validation에 유용하다는 점. 

게터스 세터스라고 하니까 지저스 바제스 형님의 이름이 생각이 나네요 위~하하하하하하하

 

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;
        }

        this._modelName = value;
    }

    get modelYear() {
        return this._modelYear;
    }
    set modelYear(value) {
        if (value.length !== 4) {
            console.log("모델명이 입력되지 않았습니다. ");
            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') {
            console.log('잘못된 타입입니다.')
        }

        // 검증 완료
        this._type = value;
    }

    get price() {
        return this._price;
    }
    set price(value) {
        if(typeof value !== 'number') {
            console.log('숫자를 입력해주세요')
        } else if (value <= 100) {
            console.log('100만원 이상부터 차로 칩니다. ')
        }

        // 검증 완료
        this._price = value;
    }

    makeNoise() {
        console.log(this.modelName + " 빵");
    }

    whenManu() {
        console.log(this.modelName + "은" + this.modelYear + " 입니다");
    }
}

const car1 = new Car("sorento", "10", "e", 1000);
const car2 = new Car("sonata", "20", "g", 1000);
const car3 = new Car("sm5", "30", "d", 1000);

console.log(car1.modelName)
car1.modelName = 1
console.log(car1.modelName)

 

게터스 세터스를 쓰는 이유는 validation 때문!

이를 활용하기 위한 예제를 한 번 작성해보았다! 

 

상속.

class -> 유산으로 내려주는 주요한 기능들. 

class Animal {
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(`${this.name} 빽!`);
    }
}

class Dog extends Animal {
    speak() {
        console.log(`${this.name} 멍!`);
    }
}

const puppy1 = new Dog("앤디");
puppy1.speak();

 

애니멀을 부모로 하여 도그라는 클래스를 만들고 스피크를 재정의했다. 이런 재정의를 오버라이드라고 한다. 

class Car {
    constructor(modelName, modelYear, type, price) {
        this.modelName = modelName;
        this.modelYear = modelYear;
        this.type = type;
        this.price = price;
    }

    makeNoise() {
        console.log(this.modelName + " 빵");
    }

    whenManu() {
        console.log(this.modelName + "은" + this.modelYear + " 입니다");
    }
}

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 elecar1 = new ElectronicCar("돌돌이", "2023", "9000", 60);
elecar1.makeNoise();
elecar1.whenManu();
console.log(elecar1._chargeTime);
elecar1.chargeTime = 20;
console.log(elecar1._chargeTime);

 

자식 요소에 새로운 요소를 추가하거나, 뺄 때는 부모를 명시해줘야함.

부모를 할 때는 super을 쓴다. 

// static 메소드 = 정적 메소드.
// Class는 객체를 만들기 위해 ㅏ용.
// 다량으로 안전하고, 정확하게.

class Calculator {
    static add(a, b) {
        // 그래서 준비했습니다. 스태틱.
        console.log("더하기");
        return a + b;
    }

    static subtract(a, b) {
        console.log("빼기");
        return a - b;
    }
}

Calculator.add(3, 5); // 일케 쓰고 시푼데.... 굳이 컨스트럭터 어쩌구저쩌구가 피료했을까?

console.log(Calculator.add(3, 5)); // 이렇게 쓸 수 있다!

 

클로저

클로저는 함수와 그 함수가 선언덴 렉시컬 환경의 조합. 

const x = 1;

function outerFunc() {
    const x = 10;
    function innerFunc() {
        // 함수가 선언된 렉시컬 환경? -> 함수가 선언될 당시의 외부 변수 등의 정보!
        console.log(x); // 이너펑크에 없으니 바로 밖의 x를 참조하기에 10. 
    }

    innerFunc();
}

outerFunc();
const x = 1;

// 1
function outer() {
  const x = 10;
  const inner = function () {
    console.log(x);
  };
  return inner;
}

const innerFunc = outer();
// ----------------- 여기서는 outer 함수의 실행 컨텍스트는...? 사라진다! 그냥 담은 것 뿐이니까.
innerFunc(); // 10.

 

클로저는 상태를 안전하게 변경하고 유지하기 위해 사용한다. 

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

 

즉시 실행 함수를 통해 값을 담는 것이 포인트.

숙제에서 고전했던 부분

function makeAnswerCircle(guess) {
  const CIRCLE_NAME = "answer";
  showCircle(guess, CIRCLE_NAME, $answerCircleArea).then((div) => {
    div.id = "answerCircle";
    div.append(CIRCLE_NAME);
  });
}

function makeGuessCircle(guess) {
  const CIRCLE_NAME = "guess";
  showCircle(guess, CIRCLE_NAME, $guessCircleArea).then((div) => {
    div.id = "guessCircle";
    div.append(CIRCLE_NAME);
  });
}

function showCircle(size, circleName, area) {
  console.log("====================================");
  console.log("맨 처음 쇼 서클");
  console.log("====================================");
  const cx = size + 20;
  const cy = size + 20;
  const radius = size + 20;

  let div = document.createElement("div");
  area.appendChild(div);

  div.id = `${circleName}`;
  div.className = "circle";
  div.style.width = 0;
  div.style.height = 0;
  div.style.left = cx + "px";
  div.style.top = cy + "px";

  return new Promise((resolve) => {
    setTimeout(() => {
      div.style.width = radius * 2 + "px";
      div.style.height = radius * 2 + "px";

      div.addEventListener("transitionend", function handler() {
        div.removeEventListener("transitionend", handler);
        resolve(div);
      });
    }, 10);
  });
}

 

마지막에 promise를 반환했으니까, then으로 끌고 갔어야지...

let a = false;
let b = true;
let c = (a || b) && false;
console.log(c);

 

연산자를 여러 개 계산할 때는 먼저 계산하고 싶은 것부터 괄호를 쳐주자 

 

function sayHello(name = "박민준") {
    console.log(`안녕 나는 ${name}이야`);
}

sayHello('dbwl')

 

이렇게 하면 기본 매개 변수를 세팅 가능하다. 

 

그리고 기본 매개 변수는 맨 끝에서부터 채운다 (중요)

 

fetch를 통해 TMDB에서 영화를 가져와 카드화하였다. 

const main = document.querySelector("main");
const cardWrapper = document.querySelector(".cardWrapper");

const options = {
    method: "GET",
    headers: {
        accept: "application/json",
        Authorization:
            "Bearer eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJlYTNkZjlkMmFlMjRiZGQ5Y2E1Y2YxZWE0YjBlZGZlZSIsIm5iZiI6MTcyODk2NDkzNy4yNDIyMjgsInN1YiI6IjY3MGRlNTdhOWYzNTMxZTZiMjZjNDU5OCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.npK2DJ6_sFT87OLxSowunNArjpxCtQ-dPQrI9ppT1yE",
    },
};

fetch(url, options)
    .then((res) => res.json())
    .then((data) => {
        console.log(data);

        for (i = 0; i < data.results.length; i++) {
            const temp = `<div class="tempcard">
            <img
                src="https://image.tmdb.org/t/p/w500/${data.results[i].poster_path}"
                alt="영화의 이미지가 표현됩니다."
                style="width: 200px; height: 300px;"
            />
            <ul class="contentWrapper">
                <li class="movieTitle">${data.results[i].title}</li>
                <li class="movieScore">평점 : ${data.results[i].vote_average}</li>
            </ul>
        </div>`;

            main.innerHTML += temp;
        }
    })
    .catch((err) => console.error("error:" + err));

 

 

처음에 조금 헤맸지만, 과거 내가 했던 작품들을 찾아보며 어떻게든 구현해내는데 성공했다. 

 

스타일링도 얼추 됐지만, 문제가 몇 가지 있는데. 일단 검색 기능을 어떻게 구현해야할 지 잘 와닿지 않는다는 점이다. 

 

음... 검색 버튼을 누르면? input된 값을 찾는 로직을 만들어야할 듯 하다. 

 

모달은 display none이나 hidden으로 된 겁나 큰 무언가를 만들고, 그 안에 클릭된(this를 통해서 클릭된 개체를 판단) 카드의 정보를 표시해주는 창구를 만들면 될 듯 하다.