
result.jsλΌλ νμΌμ λ°λ‘ λ§λ€μ΄μ resultμ κ΄λ ¨λ μ½λλ₯Ό μ΄κ³³μ μ μ΄μ€λ€. srcλΌλ ν΄λμ result.jsμ main.jsλ₯Ό ν¨κ» λ£μ΄ κ΄λ¦¬νλ€. HTML νμΌμ script μ½λ λΆλΆμ type="module"μ μ λλ€.
result.jsμμ Result λΌλ classλ₯Ό μ μΈνλ€.
constructor ν¨μλ₯Ό ν΅ν΄ result ν΄λμ€μ λ©€λ² λ³μλ₯Ό λ§λ€μ΄μ€λ€. νμν DOM μμλ₯Ό κ°μ§κ³  μμ κ·Έ μμ thisλ₯Ό μ μ΄μ€λ€. μ¬κΈ°μ thisλ Result ν΄λμ€ κ°μ²΄λ₯Ό μλ―Ένλ€.
π setClickListener λ©μλλ₯Ό λ±λ‘ν΄μ€λ€. onClickμ΄λΌλ μ½λ°± ν¨μλ₯Ό Result ν΄λμ€μ onClickμ΄λΌλ λ©€λ² λ³μμ ν λΉνλ€.
π onClick λ©€λ² λ³μκ° trueλΌλ©΄(λ±λ‘λ μ½λ°± ν¨μκ° μμΌλ©΄) κ·Έκ²μ μ€ννλ€.
Result ν΄λμ€ μμ export default λ₯Ό μ μ΄μ λ€λ₯Έ νμΌμμλ Result ν΄λμ€λ₯Ό μ½μ μ μλλ‘ ν΄μ€λ€.
'use strict';
export default class Result {
  constructor () {
    this.gameResult = document.querySelector('.result');
    this.replayBtn = document.querySelector('.replayBtn');
    this.notice = document.querySelector('.notice');
    this.replayBtn.addEventListener('click', () => {
      this.onClick && this.onClick(); // π 
      this.hide();
    });
  }
  setClickListener (onClick) { // π
    this.onClick = onClick;
  }
  show (text) {
    this.gameResult.style.display = 'block';
    this.notice.innerHTML = text;
  }
  hide () {
    this.gameResult.style.display = 'none';
  }
}
νμΌ μμ import Result from './result.js'; λΌκ³ μ μ΄μ€λ€.
Result ν΄λμ€λ₯Ό μ΄μ©ν΄ gameFinishBannerλΌλ κ°μ²΄λ₯Ό μμ±ν΄μ€λ€. κ·Έλ₯ resultλΌκ³  μ°μ§ λ§κ³ , μ νν μ΄κ² μ΄λ€ κ±΄μ§ μ€λͺ
ν΄μ£Όλ μ΄λ¦μ μ°λλ‘ νλ€.
gameFinishBannerμ setClickListener λ©μλλ₯Ό λ±λ‘ν΄μ€λ€. μ΄λ‘ μΈν΄ ν΄λ¦μ΄ λλ©΄ startGame ν¨μκ° νΈμΆλλ€.
const gameFinishBanner = new Result();
gameFinishBanner.setClickListener(() => {
  startGame();
});
/*
gameFinishBanner.setClickListener(() => startGame());
gameFinishBanner.setClickListener(startGame);
λͺ¨λ κ°μ λ»μ΄λ€.
*/
field.jsμμ Field λΌλ classλ₯Ό μ μΈνλ€.
constructor ν¨μλ₯Ό ν΅ν΄ field ν΄λμ€μ λ©€λ² λ³μλ₯Ό λ§λ€μ΄μ€λ€. fieldμ ν΄λ¦ μ΄λ²€νΈλ₯Ό λ±λ‘νμ¬ field ν΄λ¦ μ field ν΄λμ€μ λ©€λ² λ©μλμΈ onClick ν¨μκ° νΈμΆλλλ‘ μ μ΄μ€λ€.
π‘ thisμ λ°μΈλ© νλ λ°©λ²
class λ©€λ² ν¨μκ° λ€λ₯Έ ν¨μ μΈμλ‘ μ λ¬λ λλ, thisμ κ·Έ classμ μ λ³΄κ° μ μ§λμ§ μλλ€. λ°λΌμ μλμ κ°μ΄ μμ±νλ©΄, onClick ν¨μ λ³Έλ¬Έ(μλ field.js μ 체 μ½λ μ°Έκ³ )μμ this.onItemClick κ°μ΄ νμ undefinedκ° λμ΄ μ½λκ° μλν λλ‘ μ€νλμ§ μλλ€.this.field.addEventListener('click', this.onClick); // (x)
- μ΄λ₯Ό ν΄κ²°νκΈ° μν΄ μλ 3κ°μ§ λ°©λ²μ μ¬μ©ν μ μλ€.
 νμ΄ν ν¨μμμ thisλ μΈμ λ νμ΄ν ν¨μμμ μ€μ½νμ thisλ₯Ό κ°λ¦¬ν€λμ μ μ΄μ©ν΄ μμ±ν΄λΌ.β νμ΄ν ν¨μ μ΄μ© β
this.field.addEventListener('click', (event) => this.onClick(event));β νμ΄ν ν¨μ μ΄μ© β‘
// μ΄λ κ² μ μλ onClick ν¨μλ₯Ό onClick (event) { } // μ΄λ κ² λ°κΎΌλ€ onClick = (event) => { }β bind λ©μλ μ΄μ©
this.onClick = this.onClick.bind(this); this.field.addEventListener('click', this.onClick);
Field ν΄λμ€λ started, timer, limit λ± κ²μ μ§ν μνμ κ΄ν μ λ³΄λ μ²λ¦¬ν  μ μλ€. μλ fieldμμ μΌμ΄λ¬λ μ΄λ―Έμ§ λλ€ λ°°μΉ & ν΄λ¦ μ΄λ²€νΈμ κ΄λ ¨λ λΆλΆλ§ main.js μ½λμμ κ°μ Έμ¨λ€. classμ λ©€λ² λ³μλ λ©€λ² λ©μλλ‘ μ μλ κ²λ€μ΄λΌλ©΄, μμ thisλ₯Ό λΆμΈλ€.
class λ΄μ©κ³Ό μκ΄μλ λ°°κ²½ μμ μ¬μ ν¨μ λ±μ λ©λͺ¨λ¦¬ λλΉλ₯Ό λ§κΈ° μν΄ class λ°μΌλ‘ λΉΌμ μ¨μ€λ€. (μΆν μμ ν λΆλΆ)
onClick ν¨μμ if else if ꡬ문μμ this.onItemClick ν¨μκ° μ€νλ λ κ°κ° carrotκ³Ό bugλ₯Ό μΈμλ‘ μ£Όμ΄ κ΅¬λΆλλλ‘ νλ€.
'use strict';
// μ μ λ³μλ€
const CARROT_SIZE = 120;
const BUG_SIZE = 80;
const carrotSound = new Audio('sound/carrot_pull.mp3');
// field ν΄λμ€
export default class Field {
  constructor (carrotCount, bugCount) {
    this.carrotCount = carrotCount;
    this.bugCount = bugCount;
    this.field = document.querySelector('.field');
    this.fieldRect = this.field.getBoundingClientRect();
    this.field.addEventListener('click', (event) => this.onClick(event));
  }
  // μ΄λ―Έμ§ λλ€ λ°°μΉ
  init () {
    this.field.innerHTML = '';
    this._makeImg('carrot', this.carrotCount, 'img/carrot.png', CARROT_SIZE);
    this._makeImg('bug', this.bugCount, 'img/bug.png', BUG_SIZE);
  }
  // μ΄λ―Έμ§ μμ±
  _makeImg (name, count, src, size) { // μ΄ νμΌμμλ§ λΆλ¦΄ ν¨μ μμ _ νμλ₯Ό λΆμΈλ€
    for (let i = 0; i < count; i++) {
      const item = document.createElement('img');
      item.setAttribute('class', `${name}`);
      item.setAttribute('src', `${src}`);
      const coord = this._randomCoord(size);
      item.style.left = coord[0] + 'px';
      item.style.top = coord[1] + 'px';
      item.style.width = size + 'px';
      this.field.appendChild(item);
    }
  }
  // λλ€ μ’ν μμ±
  _randomCoord (size) {
    return [ ( this.fieldRect.width - size ) * Math.random(),
             ( this.fieldRect.height - size ) * Math.random() ];
  }
  // μ½λ°± ν¨μλ₯Ό class κ°μ²΄μ λ³μμ ν λΉ
  setClickListener (onItemClick) {
    this.onItemClick = onItemClick;
  }
  // fieldμ ν΄λ¦ μ΄λ²€νΈ 리μ€λ
  onClick (event) {
    const target = event.target;
    if (target.matches('.carrot')) {
      target.remove();
      playSound(carrotSound);
      this.onItemClick && this.onItemClick('carrot');
    } else if (target.matches('.bug')) {
      this.onItemClick && this.onItemClick('bug');
    }
  }
}
// λ°°κ²½ μμ
 μ¬μ ν¨μ
function playSound (sound) {
  sound.currentTime = 0;
  sound.play();
}
field.jsμ onClick ν¨μμ μλ μ΄λ―Έμ§ μμ λ μμ μ¬μμ main.jsμ onFieldItemClick ν¨μμ μ μ§ μμλ€.
initGame ν¨μμ κΈ°μ‘΄μ init() λμ gameField.init()μ μ μ΄μ£Όμλ€.
const gameField = new Field(CARROT_COUNT, BUG_COUNT);
gameField.setClickListener(onFieldItemClick);
function onFieldItemClick (item) {
  if (!started) {
    return;
  }
  if (item === 'carrot') {
    showGameLimit(--limit);
    if (limit === 0) {
      finishGame(true);
    }
  } else if (item === 'bug') {
    finishGame(false);
  }
}