가위바위보

자바스크립트 실습 5일차

Posted by WaterMinCho on June 01, 2021 · 1053 lines

가위바위보

2021.04.30

소스코드: rsp.html


플로우

  • 알고리즘

배운 개념

1. style.background
2. setInterval()
3. 버그 해결
 - 가정
 - 해결 방법


  • style.background

    • $computer.style.background = `url(${IMG_URL}) 0 0`;
      스타일의 background이미지 X좌표 Y좌표값을 입력할 수 있다.

    • const rspX = {
        scissors: "0",
        rock: "- 230px",
        paper: "-440px",
      };
      

      위와 같이 공통된 속성을 지닌 변수의 모임은 객체로 묶어주는 것이 현명하다.

    • $computer.style.background = `url(${IMG_URL}) ${rspX[computerChoice]} 0`;
      $computer.style.backgroundSize = "auto 200px";
      
      • rspX.computerChoice하면 안된다. 왜냐하면 rspX객체엔 computerChoice라는 문자열 속성이 없기 때문에 rspX[computerChoice]로 선택해야 한다.

      • background를 수정할 때마다 size도 초기화되기 때문에 항상 background와 backgroundSize는 붙어있어야 한다.


  • setInterval(함수,반복간격(ms));

    • setInterval함수는 return값이 존재한다. 그 값은 타이머에 대한 아이디(숫자)로 해당 값을 사용하여 타이머를 제거할 수 있다.
    • setInterval을 취소할 수 있는 방법으로 clearInterval을 제공한다.
      let ID= setInterval(함수,ms)
    • setTimeout함수도 clearTimeout으로 제거할 수 있지만 setTimeout함수 내의 인수로 넣은 함수가 실행되기 전에 clearTimeout을 호출해야 한다.

  • 버그

    const clickButton = () => {
      //버튼을 눌렀을 때
      clearInterval(intervalId); // 타이머 멈춤.
      //점수 계산 및 화면 표시
      setTimeout(() => {
        intervalId = setInterval(changeComputerHand, 50); //타이머를 만들 때마다 변수에 저장한 후에 clearInterval해야 한다.
      }, 1000); //1초 뒤에 다시 setInterval.
    };
    
    $rock.addEventListener("click", clickButton);
    $scissors.addEventListener("click", clickButton);
    $paper.addEventListener("click", clickButton);
    
    • setTimeout설정값 1초 내에 여러 번 클릭하면 그림이 빠르게 돌아간다. 그 후에 버튼을 클릭하면 그림이 멈추지 않는다.
      버튼을 클릭할 떄마다 각각 setTimeout타이머가 여러 개 실행되기 떄문이다.
    • 버튼클릭을 하면 clearInterval을 수행하므로 문제없다고 생각할 수도 있다.
      하지만 버튼은 setInterval을 멈추는 clearInterval을 수행할 뿐 setTimeout을 멈추는 clearTimeout을 수행하지는 않아서 버튼을 누른 횟수만큼 setTimeout타이머가 실행되고 각각1초 뒤에 setInterval을 하게 되어 그림이 빠르게 돌아가는거다.

    • 가정
      1. clickButton을 1초 내에 10번을 눌렀다.
      2. interval의 ID인덱스로 따지면 10개가 생기지만 덮어씌우는 방식이기 때문에 마지막 인덱스를 intervalID변수에 넣고 있다.
      3. 1초 뒤에 버튼을 클릭하면 마지막 인덱스만 클리어된다.

    • 해결 방법
      1. clearInterval함수 한번 더 사용.(추천) clickButton이 실행되는 최초에 한번 클리어하고
        1초 뒤 실행되는 setTimeout에 한번 더 클리어를 하면
        1초루프동안마다 클리어가 반복되므로 해결됨.

        const clickButton = () => {
          clearInterval(intervalId);
        
          setTimeout(() => {
            clearInterval(intervalId); //추가.
            intervalId = setInterval(changeComputerHand, 50);
          }, 1000);
        };
        $rock.addEventListener("click", clickButton);
        $scissors.addEventListener("click", clickButton);
        $paper.addEventListener("click", clickButton);
        
      2. removeEventListener메서드 사용(비추천: 실수하기 쉬움)
        이유: func() !== func()라는(객체 참조관계) 개념을 사용하여 addEventListenerremoveEventListener내의 해결 법: 함수가 같아야 제거가 되는데 같지 않기 때문에 제거가 안되는 점을 놓치기 때문.
        func() === func()값이 false를 반환하기 때문에 객체(함수)를 번수에 넣으면 비교할 수 있다.
        참고) 참조관계를 유지하고 싶으면 변수에 넣으면 된다!

        const clickButton = () => {
          $rock.removeEventListener("click", clickButton); //추가.
          $scissors.removeEventListener("click", clickButton); //추가.
          $paper.removeEventListener("click", clickButton); //추가.
          //clickButton이 실행되는 최초에 한번 제거
        
          setTimeout(() => {
            $rock.addEventListener("click", clickButton); //추가.
            $scissors.addEventListener("click", clickButton); //추가.
            $paper.addEventListener("click", clickButton); //추가.
            //1초 뒤 실행되는 setTimeout마다 실행
            intervalId = setInterval(changeComputerHand, 50);
          }, 1000);
        };
        $rock.addEventListener("click", clickButton);
        $scissors.addEventListener("click", clickButton);
        $paper.addEventListener("click", clickButton);
        
      3. 플레그 변수 사용(추천)

        let clickable = true; //추가.
        const clickButton = () => {
          if (clickable) {
            clearInterval(intervalId);
            clickable = false; //추가.
            setTimeout(() => {
              clickable = true; //추가.
              intervalId = setInterval(changeComputerHand, 50);
            }, 1000);
          }
        };
        

  • diff === '고양이' || diff === '사자' || diff === '강아지' || diff === '거북이'
    위와 같은 경우는 아래와 같이 바꿀 수 있다.
    ['고양이','사자','강아지','거북이']. includes(diff)
    또는
    ['고양이','사자','강아지','거북이']. indexOf(diff) > -1