[TIL] 210929

📝 오늘 한 것

  1. false / if 구문 / && 연산자 / 빈 오브젝트 / class / 콜백 함수

  2. 당근 클릭 게임 구현 중


📖 학습 자료

  1. 드림코딩 유튜브 '자바스크립트 기본 1 ~ 4편'

  2. 드림코딩 '프론트엔드 필수 브라우저 101' 강의


📚 배운 것

드림코딩 유튜브 자바스크립트 기본 (3 ~ 4편) 참고

1. 자바스크립트 이론 보충

1) false / if 구문 / && 연산자 / 빈 오브젝트

  • 오브젝트가 값을 가지는 경우
let obj = { // obj가 값을 가지므로
  name: 'ellie'
};

if (obj) { // true이기 때문에
  console.log(obj.name); // console 창에 ellie가 출력됨
}

// 💡 그러나 위처럼 쓰는 것보다 아래처럼 쓰는 게 더 좋다

obj && console.log(obj.name); // 마찬가지로 ellie가 출력됨
  • 빈 오브젝트인 경우
let obj = {}; // 변수 obj에 빈 오브젝트더라도 값은 할당된 상태

if (obj) { // 빈 오브젝트도 그 자체로 true이기 때문에
  console.log(obj.name); // console 창에 undefined가 '출력됨'
}

obj && console.log(obj.name); // 마찬가지로 undefined가 출력됨
  • 아예 변수에 값이 할당되지 않은 경우
let obj; // 변수 obj에 어떤 값도 할당되지 않았기에 undefined

if (obj) { // undefined는 false이므로
  console.log(obj.name); // console.log가 실행되지 않아 console 창에 아무것도 '출력되지 않음'
}

obj && console.log(obj.name); // 마찬가지로 아무것도 출력되지 않음

2) class와 콜백 함수

// class 선언
class Counter {
  constructor () {
    this.counter = 0;
  }

  increase () {
    this.counter++;
    console.log(this.counter);

    // counter 변수가 5의 배수일 때마다 console 창에 '메롱' 출력
    if (this.counter % 5 === 0) {
      console.log('메롱');
    }
  }
}

// Counter라는 class를 이용해 coolCounter라는 객체를 만듦
const coolCounter = new Counter();

coolCounter.increase(); // 1
coolCounter.increase(); // 2
coolCounter.increase(); // 3
coolCounter.increase(); // 4
coolCounter.increase();
// 5
// 메롱

이렇게 쓰면 if 구문이 class 안에 들어가 있어서 수정이 어렵다.
이와 같은 경우에 콜백 함수(다른 함수에 인자로 들어가는 함수)를 이용할 수 있다.

class Counter {
  constructor () {
    this.counter = 0;
  }
  
  // increase 메서드의 인자로 함수를 넣어줌
  increase (runIf5Times) {
    this.counter++;
    console.log(this.counter);

    if (this.counter % 5 === 0) {
      runIf5Times(); // console.log('메롱'); 대신 써줌
    }
  }
}

const coolCounter = new Counter();


// increase 메서드의 인자로 printSomething 함수를 넣어줌
function printSomething () {
  console.log('메롱');
}
coolCounter.increase(printSomething);
coolCounter.increase(printSomething);
coolCounter.increase(printSomething);
coolCounter.increase(printSomething);
coolCounter.increase(printSomething);
// 위와 같은 결과가 뜬다

콜백 함수에도 인자를 전달할 수 있다.

class Counter {
  constructor () {
    this.counter = 0;
  }

  increase (runIf5Times) {
    this.counter++;
    console.log(this.counter);

    if (this.counter % 5 === 0) {
      runIf5Times(this.counter); // this.counter를 써줌
    }
  }
}

const coolCounter = new Counter();

function printSomething (num) { // 콜백 함수에 인자를 넣어줌
  console.log(`메롱 ${num}`);
}

coolCounter.increase(printSomething); // 1
coolCounter.increase(printSomething); // 2
coolCounter.increase(printSomething); // 3
coolCounter.increase(printSomething); // 4
coolCounter.increase(printSomething);
// 5
// 메롱 5

class에 미리 정의해놓는 게 아니기 때문에 그때그때 다른 콜백 함수를 만들어 인자로 전해줌으로써 다양한 기능을 수행할 수 있다.

class Counter {
  constructor () {
    this.counter = 0;
  }

  increase (runIf5Times) {
    this.counter++;
    console.log(this.counter);

    if (this.counter % 5 === 0) {
      runIf5Times(this.counter);
    }
  }
}

const coolCounter = new Counter();

// alertNum이라는 콜백 함수를 새로 만듦
function alertNum (num) {
  alert(`우와 ${num}`);
}

coolCounter.increase(printSomething);
coolCounter.increase(printSomething);
coolCounter.increase(printSomething);
coolCounter.increase(printSomething);
coolCounter.increase(alertNum);

그러나 이렇게 하면 매번 coolCounter 객체의 increase 메서드에 콜백 함수를 써줘야 해서 번거롭다.
이 문제는 애초에 class로 객체를 만들 때 생성자(coustructor) 함수에 원하는 콜백 함수를 전달함으로써 해결할 수 있다.

class Counter {
  constructor (runEveryFiveTimes) { // 1. 생성자 함수에 매개변수를 적어줌
    this.counter = 0;
    this.callBack = runEveryFiveTimes; // 2. 객체의 callBack이란 속성에 매개변수를 할당함
  }

  increase () {
    this.counter++;
    console.log(this.counter);

    if (this.counter % 5 === 0) {
      this.callBack(this.counter);
      // 5. this.callBack에 할당되어 있는 printSomething 함수를 호출하라는 뜻
      // 6. 이 함수가 실행될 때는 this.counter가 인자로 들어감
    }
  }
}

// 3. printSomething이란 콜백 함수를 선언함
function printSomething (num) {
  console.log(`우와 ${num}`);
}

const printCounter = new Counter(printSomething);
// 4. 그 매개변수는 printSomething이란 것인데, 이는 앞에서 정의했다시피 함수임

coolCounter.increase();
coolCounter.increase();
coolCounter.increase();
coolCounter.increase();
coolCounter.increase();
// 7. coolCounter 객체의 increase 메서드를 실행해 this.counter가 5의 배수가 되면
// 그때의 this.counter를 인자로 가지는 printSomething 함수가 실행됨

// 8. alertNum이라는 또 다른 콜백 함수를 선언해 같은 순서를 거칠 수 있음
function alertNum (num) {
  alert(`우와 ${num}`);
}

// 💡 Counter라는 하나의 class를 이용해 서로 다른 기능을 수행하는 다양한 객체를 만들 수 있다
// → class의 재사용 가능성 ↑
const alertCounter = new Counter(alertNum);

coolCounter2.increase();
coolCounter2.increase();
coolCounter2.increase();
coolCounter2.increase();
coolCounter2.increase();

위의 경우에는 Counter라는 class를 이용해 coolCounter라는 객체를 만들 때 따로 콜백 함수를 등록해준 경우이다.

그러나, 만약 콜백 함수를 등록해주지 않았다면 this.callBack은 undefined 값을 갖게 된다.

이렇게 되면 위의 if 구문에서 함수가 아닌 this.callBack을, 함수를 호출하듯이 호출해버린 것이 되어, this.callBack은 함수가 아니라는 typeError가 뜨게 된다.

따라서, 이런 에러의 발생을 막기 위해서는 등록된 콜백 함수가 있는지 없는지(this.callBack이 undefined인지 아닌지)를 확인한 후 전자일 때만 콜백 함수를 부르도록 해야 한다.

이를 위해 increase() 메서드의 코드 블럭을 아래와 같이 수정해줄 수 있다.

increase() {
  this.counter++;
  console.log(this.counter);

  if (this.callBack) {
    this.counter % 5 === 0 && this.callBack(this.counter);
}

2. 자바스크립트 실전

1) 당근 클릭 게임 만들기

📌 구현 내용 쪼개기

  1. 초기 화면에 보여야 할 것들

1) 게임 시작 버튼
2) 타이머 (0:0이라고 적혀 있음)
3) 클릭 가능 횟수 (0이라고 적혀 있음)

  1. 게임 시작 버튼을 클릭하면

1) 필드 안에 당근 10개과 벌레 7마리가 랜덤한 위치에 배치되어야 한다.
2) 타이머가 작동해야 한다. (10초부터 시작)
3) 클릭 가능 횟수가 10으로 바뀌어야 한다.
4) bg.mp3 배경음이 재생되어야 한다.
5) 게임 시작 버튼 안의 아이콘이 중지 아이콘으로 바뀌어야 한다.

  1. 당근을 클릭하면

1) carrot_pull.mp3 효과음이 들려야 한다.
2) 클릭 가능 횟수가 1씩 줄어들어야 한다.
3) 클릭된 당근이 화면에서 사라져야 한다.

  1. 벌레를 클릭하면

1) bg.mp3 배경음이 멈춰야 한다.
2) bug_pull.mp3 효과음이 들려야 한다.
3) 타이머가 멈춰야 한다.
4) 게임 시작 버튼이 없어져야 한다.
5) YOU LOST 문구와 함께 재시작 버튼이 떠야 한다.

  1. 제한 시간 내에 모든 당근을 클릭하면

1) bg.mp3 배경음이 멈춰야 한다.
2) game_win.mp3 음악이 재생되어야 한다.
3) 타이머가 멈춰야 한다.
4) 게임 시작 버튼이 없어져야 한다.
5) YOU WON 문구와 함께 재시작 버튼이 떠야 한다.

  1. 제한 시간 내에 모든 당근을 클릭하지 못하면

1) bg.mp3 배경음이 멈춰야 한다.
2) 게임 시작 버튼이 없어져야 한다.
3) YOU LOST 문구와 함께 재시작 버튼이 떠야 한다.

  1. 게임 중지 버튼을 클릭하면

1) bg.mp3 배경음이 멈춰야 한다.
2) alert.wav 효과음이 들려야 한다.
3) 타이머가 멈춰야 한다.
4) 게임 시작 버튼이 없어져야 한다.
5) REPLAY 문구와 함께 재시작 버튼이 떠야 한다.

  1. 재시작 버튼을 클릭하면

1) 이전 게임의 당근과 벌레가 없어져야 한다.
2) replay ❓ 창이 없어져야 한다.
3) 다시 2.가 일어나야 한다. - (1), (3)만
4) 타이머가 '다시 처음부터' 작동해야 한다.
5) bg.mp3 배경음이 '다시 처음부터' 재생되어야 한다.
6) 게임 시작 버튼이 다시 보여야 한다.


(1) 첫 번째 요구 사항

초기 화면에 보여야 할 것들

  • 게임 시작 버튼
  • 타이머 (00:00이라고 적혀 있음)
  • 클릭 가능 횟수 (0이라고 적혀 있음)

📌 HTML 마크업

추후 수정

<html>
  <body>
    <div class="setting">
      <button class="setting-startBtn" type="button"><i class="fas fa-play"></i></button>
      <div class="setting-timer">00:00</div>
      <div class="setting-limit">0</div>
    </div>
    <div class="field"></div>
  </body>
</html>

📌 CSS 스타일링

추후 수정

  • background: color image_url attatchment position / size;
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

button {
  border: 5px solid black;
  border-radius: 20px;
  background-color: wheat;
  width: 100px;
  height: 100px;
}

html {
  width: 100%;
  height: 100%;
}

body {
  background: url("img/background.png") no-repeat center / cover;
}

.setting {
  height: 450px;
}

.setting-startBtn {
  display: block;
  margin: 15px auto;
}

.setting-timer {
  border: 5px solid black;
  border-radius: 20px;
  background-color: white;
  width: 260px;
  height: 80px;
  margin: 15px auto;
  text-align: center;
  font-size: 2.5em;
  line-height: 1.3;
}

.fas {
  font-size: 40px;
}

.setting-limit {
  border: 4px solid black;
  border-radius: 50%;
  background-color: orange;
  width: 100px;
  height: 100px;
  margin: 10px auto;
  text-align: center;
  line-height: 1.5;
  font-size: 3em;
  font-weight: bold;
}

.field {
  height: calc(100vh - 450px);
}

(2) 두 번째 요구 사항

게임 시작 버튼을 클릭하면

  • 필드 안에 당근과 벌레들이 랜덤한 위치에 배치되어야 한다.
  • 타이머가 작동해야 한다. (10초부터 시작)
  • 클릭 가능 횟수가 10으로 바뀌어야 한다.
  • bg.mp3 배경음이 재생되어야 한다.
  • 게임 시작 버튼 안의 아이콘이 중지 아이콘으로 바뀌어야 한다.

(아직 구현 중)

📌 JavaScript 작성

const startBtn = document.querySelector('.setting-startBtn');
const timer = document.querySelector('.setting-timer');
const clickLimit = document.querySelector('.setting-limit');

// 게임 시작 버튼을 클릭하면
let time = 10;

startBtn.addEventListener('click', function startTimer () {
  // 타이머가 작동해야 한다.
  const decreNum = setInterval(function () {
    const second = time % 60;
    timer.innerHTML = `0:${second}`;
    time--;

    if (time < 0) {
      clearInterval(decreNum);
    }
  }, 1000);
  
  // 클릭 가능 횟수가 10으로 바뀌어야 한다.
  clickLimit.innerHTML = 10;
});

좋은 웹페이지 즐겨찾기