웹 게임을 만들며 배우는 JS : 로또추첨기 Math.random(), Math.floor/ceil/round, forEach와map, for반복문과while반복문사용차이, .sort(오름차순정렬) setTimeout(function (){} , 밀리초) 1. Math.random() 랜덤한 수를 뽑는 매서드이다.
1 2 3 4 5 6 Math .random() 에서 * n을 하면, n전까지의 숫자가 random으로 나온다.보기쉽게 소수점첫째자리 버림 하는 함수인 Math .floor()와 함께 주로 사용한다. 예를들어 Math .floor(Math .random()*5 )
2. Math.floor()와 Math.ceil()와 Math.round() 세가지의 차이점은
1 2 3 Math.floor() : 소수점 버림. 정수로 반환. Math.ceil() : 소수점 올림. 정수로 반환. Math.round() : 소수점 반올림. 정수로 반환.
3. .forEach(function(){})와 .map(function(){}) STEP1. 로또 숫자 만들기(1~45까지)
1 2 3 4 5 6 7 8 9 10 11 12 var 후보군 = Array (45 ); var 필 = 후보군.fill(); 필.forEach(function (요소,인덱스 ) { 필[인덱스] = 인덱스 + 1 ; }); console .log(필);
더 좋은 방법이 있다. 바로 maping이다. .map(function(){})은 array 요소와 1대1로 mapping이 된다.
1 2 3 4 5 6 7 8 var 후보군 = Array (45 ); var 필 = 후보군.fill(); var 맵 = 필.map(function (요소, 인덱스 ) { return 인덱스 + 1 }); console .log(맵);
굳이 변수를 3개씩 많이 지정할 필요가 없다. 위의 전체를 변수 1개로 그리고 단 세 줄로 나타낼 수 있다.
1 2 3 4 5 var 후보군 = Array (45 ).fill().map(function (요소, 인덱스 ) { return 인덱스 + 1 }); console .log(후보군);
세상 깔~끔!
4. for반복문과 while반복문 사용차이 STEP2. 숫자를 랜덤하게 섞고 총7개 숫자를 뽑기
숫자를 랜덤하게 섞은 뒤 7가지의 숫자를 뽑고자 한다면 흔히 for문을 먼저 생각할 것이다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var 셔플 = [];for (var i=0 ; i<후보군.length; i+=1 ){ var 이동값 = 후보군.splice(Math .floor(Math .random()*후보군.length), 1 )[0 ]; 셔플.push(이동값); } console .log('---' )console .log('후보군길이: ' +후보군.length); console .log('셔플길이: ' +셔플.length); console .log('후보군: ' +후보군.sort(function (p, c ) { return p-c;})); console .log('셔플숫자: ' +셔플.sort(function (p, c ) { return p-c;}));
하지만 for반복문을 못 쓰지 못한다.
후보군길이 + 셔플길이 = 45 개 된다. 즉, 기존 후보군길이 45개에서 셔플로 23개 빠지고 나머지 22개만 남게된다.
후보군.length가 45개에서 22개로 줄어들면 우리가 원하는데로 45개에서 랜덤숫자 7개를 뽑을 수 없다.
지금 23개에서 랜덤숫자 7개 뽑는 꼴이 되버림. 따라서 이럴 때는 while을 쓴다.
1 2 3 4 5 6 7 8 9 10 11 12 13 while (후보군.length>0 ){ var 이동값 = 후보군.splice(Math .floor(Math .random()*후보군.length), 1 )[0 ]; 셔플.push(이동값); } console .log('---' )console .log('후보군길이: ' +후보군.length); console .log('셔플길이: ' +셔플.length); console .log('후보군: ' +후보군.sort(function (p, c ) { return p-c;})); console .log('셔플숫자: ' +셔플.sort(function (p, c ) { return p-c;}));
for반복문은 내가 몇번 반복해야할 지 정확히 알 때 사용하면 좋고,
while반복문은 내가 몇번 반복해야할 지 모를 때, 그리고 기준값이 계속 변경될때 사용하면 좋다.
여기서 기준값은 후보군.length다.
이렇게 뽑은 랜덤한 7개의 숫자는 아직 console.log를 통해 볼 수 밖에 없다.
따라서 화면에 구현하는 방법은 html로 결과창태그를 만든 뒤
js상으로 결과창태그를 불러와서 뽑은 랜덤당첨숫자들이 결과창태그의 자식태그로 들어가면 된다.
1 2 3 <div id ='결과창' > <div > 여기에 각 당첨숫자태크가 갯수만큼 자동으로 생겨야함<div > //그렇다면 for문이겠지? </div >
1 2 3 4 5 6 7 8 9 var 결과창 = document .getElementById('결과창' );for (let i=0 ; i<당첨숫자들.length; i+=1 ){ var 공 = document .createElement('div' ); 공.textContent = 당첨숫자들[i]; 결과창.appendChild(공); }
5. JS에서 html태그를 불러오는 2가지 방법 첫번째, getElementById 와 getElementsByClassName 를 이용하기
두번째, querySelector 와 querySelectorAll를 이용하기(권장)
1 2 3 4 5 6 7 <body > <div > 당첨 숫자는? ㄷㄱㄷㄱㄷㄱ</div > <div id ='결과창' > </div > <div > 보너스숫자</div > <div class ='보너스' > </div > <script src = "로또추첨기.js" > </script > </body >
이 태그들 중 결과창과 보너스를 js로 가져오는 방법은
1 2 3 4 5 6 7 var 결과창 = document .getElementById('결과창' ); var 칸 = document .getElementsByClassName('보너스' )[0 ]; var 결과창 = document .querySelector('#결과창' ); var 칸 = document .querySelector('.보너스' );
끝! 이렇게 가지고 와서 원하는 방향으로 사용하면 된다!
6. .sort와 .sort(function(p, c){ return p-c;}) 1 2 3 .sort() : 숫자 정렬 예를들어 [2 ,15 ,4 ,7 ,27 ].sort();
뭔가 이상한데?
첫째자리 수를 기준으로 숫자 오름차순이라서 그렇다.
15에 1이 먼저 있기때문에 15가 제일 첫번째로 정렬되었다.
우리가 원하는 오름차순은 아래와 같다. 내림차순은 덤으로 공부!
1 2 3 4 5 6 7 .sort(function (p, c ) { return p-c;}) : 숫자오름차순 정렬 예를들어 [2 ,15 ,4 ,7 ,27 ].sort(function (p, c ) { return p-c;}) .sort(function (p, c ) { return c-p;}) : 숫자내름차순 정렬 예를들어 [2 ,15 ,4 ,7 ,27 ].sort(function (p, c ) { return c-p;})
어떠한 원리로 정렬이 되는 걸까?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 [25 ,1 ,12 ].sort(function (p, c ) { return p-c;}) p - c 25 - 1 = 24 p - c 25 - 12 = 13 p - c 1 - 12 = -11 p - c 12 - 25 = -13
숫자뿐만 아니라 문자도 비슷한 원리로 정렬이 된다고 한다.
7. setTimeout(function (){} , 밀리초) STEP3. 화면에 로또숫자를 긴장감있게 나타내기
랜덤 숫자들이 화면에 한꺼번에 보여지는 게 아니라 시간차를 두고 나타나게 하고 싶다면 setTimeout(function (){} , 밀리초) 을 사용하면 된다.
1 2 3 4 5 setTimeout(function ( ) { var 공 = document .createElement('div' ); 공.textContent = 당첨숫자들[0 ]; 결과창.appendChild(공); }, 1000 );
for문사용시 클로저문제가 발생하므로 당첨숫자들[0] ~ 당첨숫자들[5]까지 각각 적어준다.
나는 쪼랩이라 아직 클로저문제 해결법을 안 알려준다고 한다ㅋㅋㅋㅋ 나중에 중급강의에 알려준다고 하니 그때 해야지.
그럼 어떻게 하느냐? for문을 안 쓰면 된다
당첨숫자들[0] ~ 당첨숫자들[5]까지 각각 적어준다.
만약 클로저를 이용해서 푼다면 아래와 같다
1 2 3 4 5 6 7 8 for (var i=0 ; i<당첨숫자들.length; i+=1 ){ function 클로저(j ) { setTimeout(function ( ) { 공색칠하기(당첨숫자들[j], 결과창); },(j+1 ) * 1000 ); } 클로저(i); }
이걸 더 짧게 줄일 수가 있는데 바로 즉시실행코드를 이용하면 된다
function을 괄호로 감싸면 즉시실행코드가 된다
1 2 3 4 5 6 7 for (var i=0 ; i<당첨숫자들.length; i+=1 ){ (function 클로저(j ) { setTimeout(function ( ) { 공색칠하기(당첨숫자들[j], 결과창); },(j+1 ) * 1000 ); })(i); }