로또 추첨기/자바스크립트 프로그래밍 강좌
==============
1부터 45까지
6개
그리고
보너스 숫자 하나더 해서
총 7개를 뽑으면 되는건데
그래서 로또 추첨기를 만들어 볼껀데요.
=====================================
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
숫자를 45까지 만들어야되는데 이렇게 치고있으면 폼이 안나니까 만들어봅시다..
후보군[1] //undefined
후보군[2] //undefined
후보군[3] /undefined
후보군[4] //undefined
[undefined, undefined ,undefined].forEach(function(요소){
console.log(요소);
})
// undefined
var 후보군 = Array(45); // [ ]
var 필 = 후보군.fill(); // 후보군45개 언디파인드를 필에다 넣은거
console.log(필);
1부터 45 넣는 방법
필.forEach(function(요소, 인덱스){
console.log(요소, 인덱스);
})

// 그럼 이렇게 나온다
요소 인덱스 이렇게
나온다
인덱스를 활용하면 할수있는게
1부터 45까지를
그니까
0부터 44까지 해서 +1을 더해주면
1부터 45 까지가 되는거다
필.forEach(function(요소, 인덱스){
console.log(요소, 인덱스 + 1);
})
문제는 더이상 애를 어떻해 할수는 없다 그냥 콘솔 로그만 찍을수 있지
뭘할수있는게 없다...
뭘 억지로 한다 치면,,,
필.forEach(function(요소, 인덱스){
필[인덱스] = 인덱스 +1;
});
console.log(필);
찍으면

이런식으로..
근데 이렇게 forEach로 하는건 좀 억지스럽다..
어쨋뜬
우리가 원하는건
후보군 45 에서
[undefined, undefined ,undefined ];
이거를
[1 ,2 ,3]
이렇게 숫자로 바꾸는 작업이다.
1:1로 짝지어 주잖아요...
첫번째 언디파인드를 1 로
두번째 언디파인드를 2 로
세번쨰를 3으로
이렇게 하나씩 짝지어주는것
이걸 맵이라고 부른다
맵핑 한다!이렇게 부르는데
forEach 대신에
map 이라고 있는데
이걸 쓰면(맵으로 배열을 만들어서,,)
var 맵 = 필.map(function(요소,인덱스){
return 1;
});
console.log(맵);
이렇게 해주면, 이렇게 리턴에 1을 해주면

1 이 주루룩 나온다
그래서
이번에는
1:1 맵핑을 해주면
var 맵 = 필.map(function(요소,인덱스){
return 인덱스;
});
console.log(맵);

0 부터 44까지 나온다
이걸 1부터 45 로 나오게 만들려면 1 을 더해주면된다
var 맵 = 필.map(function(요소,인덱스){
return 인덱스 + 1;
});
console.log(맵);
이렇게하면 1부터 45까지 뽑는다.
근데 코드가 긴데,,이걸 한방에 줄이려면
var 맵 = Array(45).fill().map(function(요소,인덱스){
return 인덱스 + 1;
});
하면 한방에 되는거다.
또 애를 다시 후보군이라고 하면
var 후보군 = Array(45)
.fill()
.map(function(요소,인덱스){
return 인덱스 + 1;
});
console.log(후보군);
이렇게 할수 있다.
이제 여기서 숫자들을 뽑는거를 해보겠다
// 1 부터 45까지 있으면 그중에서 6개를 뽑으면 되는거니까
//그 6개를 뽑는게 보통 셔플을 많이 쓴다.
//예를들어 1부터 45까지 숫자가 있으면 그걸 랜덤하게 섞는다
// 그 다음 앞에서부터 6개나, 뒤에서부터 6개를 짤라서 출력해주는 방식이 셔플
// 우리가 해볼것은 숫자를 섞고 앞에서 6개 뽑고 , 보너스 숫자는 맨 뒤에서 1개를 뽑는 코드를 만들어보자
//
//일단 후보군의 숫자를 하나씩 뽑을껀데,
//for문을 써서하면
// 숫자를 하나씩 뽑으면 후보군의 숫자가 하나씩 줄어들기 떄문에
// 45 44 43 42 41 이렇게 계속 줄어들기때매
//이 방식은 안할꺼다
var 후보군 = Array(45)
.fill()
.map(function(요소,인덱스){
return 인덱스 + 1;
});
console.log(후보군);
var 셔플 = [];
for (var i = 0; i < 후보군.length ; i += 1 ){
}
//이렇게 for문을 써버리면....
카운트 후보군숫자 / 후보군남은숫자
0 1 / 44
1 2 / 43
2 3 / 42
3 4 / 41
4 5 / 40
5 6 / 39
6 7 / 38
7 8 / 37
8 9 / 36
9 10 / 35
10 11 / 34
11 12 / 33
12 13 / 32
13 14 / 31
14 15 / 30
15 16 / 29
16 17 / 28
17 18 / 27
18 19 / 26
19 20 / 25
20 21 / 24
21 22 / 23
22 23 / 22
이렇게 더이상 사용할수가 없다.그냥 22 에서 끝나버린다
그래서 for문은 안쓴다
이럴떄는 while 을 써서 한다
아까전에
for (var i = 0; i < 후보군.length ; i += 1 ){
}
//이 코드는 0 부터 45까지 돌리는데
// 기준값이 계속 바뀐다
//여기서 기분값은 후보군.length 인데 이부분이 계속 반복문을 돌리면 줄어드니까...계속 바뀌니까 왜 바뀌냐면 우리가 후보군에서 숫자를 하나씩 뽑아서 셔플에다 하나씩 넣을것이기 떄문이다.
//아무튼 이렇게 기준값이 계속 바뀌니까 이럴땐 for문 보다는 while을 쓰는게 낫다.
var 후보군 = Array(45)
.fill()
.map(function(요소,인덱스){
return 인덱스 + 1;
});
console.log(후보군);
var 셔플 = [];
while (후보군.length > 0 ){ //while로 변경!!
Math.floor(Math.random() * 후보군.length ) // 이러면 0부터44까지나오니까
}
//그래서 코드를 아래에 더 추가하면!
while (후보군.length > 0 ){ //while로 변경!!
var 이동값 = Math.floor(Math.random() * 후보군.length , 1 )[0];
셔플.push(이동값);
}
console.log(셔플);
//이렇게!!

위에는 원래 후보값
밑에는 랜덤하게 섞인 후보값
이 나온다.
그래서
var 후보군 = Array(45)
.fill()
.map(function(요소,인덱스){
return 인덱스 + 1;
});
console.log(후보군);
var 셔플 = [];
while (후보군.length > 0 ){
var 이동값 = 후보군.splice(Math.floor(Math.random() * 후보군.length) , 1 )[0];
셔플.push(이동값);
}
console.log(셔플);
//이렇게 코드를 정리하고 수정해서 로그를찍으면!!

이런식으로 랜덤한 숫자가 밑에 찍힌다.
그리고
var 후보군 = Array(45)
.fill()
.map(function(요소,인덱스){
return 인덱스 + 1;
});
console.log(후보군);
var 셔플 = [];
while (후보군.length > 0 ){
var 이동값 = 후보군.splice(Math.floor(Math.random() * 후보군.length) , 1 )[0];
셔플.push(이동값);
}
console.log(셔플);
var 보너스 = 셔플[셔플.length - 1]; //마지막숫자 가져오는법
이코드를 마지막에 추가해서 마지막 숫자를 가져온다
셔플의 length가 45이고 45 빼기 1 하면 44니까
0부터 44번쨰의 숫자를 뽑으면 마지막 숫자다
그래서
마지막 숫자가 선택된 것이다.
컴퓨터는 0부터 순서를 세니까요
그리고
var 후보군 = Array(45)
.fill()
.map(function(요소,인덱스){
return 인덱스 + 1;
});
console.log(후보군);
var 셔플 = [];
while (후보군.length > 0 ){
var 이동값 = 후보군.splice(Math.floor(Math.random() * 후보군.length) , 1 )[0];
셔플.push(이동값);
}
console.log(셔플);
var 보너스 = 셔플[셔플.length - 1];
var 당첨숫자들 = 셔플.slice(0 , 6); // slice 는 배열을 짤라서 가져오는거다
// 0 1 2 3 4 5 이렇게 가져옴 이게 6으로 계산된다 컴퓨터는 0부터 세니까
그래서
var 후보군 = Array(45)
.fill()
.map(function(요소,인덱스){
return 인덱스 + 1;
});
console.log(후보군);
var 셔플 = [];
while (후보군.length > 0 ){
var 이동값 = 후보군.splice(Math.floor(Math.random() * 후보군.length) , 1 )[0];
셔플.push(이동값);
}
console.log(셔플);
var 보너스 = 셔플[셔플.length - 1];
var 당첨숫자들 = 셔플.slice(0 , 6);
console.log('당첨숫자들',당첨숫자들, '보너스' , 보너스);
//콘솔로그로 찍어보면!!

이렇게 로그가 정상적으로 찍힌다
그래서 여기까지해서
로또추첨기를 로그로만 찍히는건 다 했고
이제 화면에 나타내줄껀데,,
그전에 sort() 정렬을 써서 당첨숫자들에 나타내게해보면
console.log('당첨숫자들',당첨숫자들.sort(), '보너스' , 보너스);
// 여기 콘솔로그에서 sort를 붙여주면 정렬이된다
//여기서 그냥 sort붙이면 원하는대로 정렬은 안되고 소트에 함수를 붙여줘야된다
console.log('당첨숫자들',당첨숫자들.sort(function(a , b){
return a - b;
}), '보너스' , 보너스);
이렇게 해서
전체코드로 적용시키면
var 후보군 = Array(45)
.fill()
.map(function(요소,인덱스){
return 인덱스 + 1;
});
console.log(후보군);
var 셔플 = [];
while (후보군.length > 0 ){
var 이동값 = 후보군.splice(Math.floor(Math.random() * 후보군.length) , 1 )[0];
셔플.push(이동값);
}
console.log(셔플);
var 보너스 = 셔플[셔플.length - 1];
var 당첨숫자들 = 셔플.slice(0 , 6);
console.log('당첨숫자들',당첨숫자들.sort(function(a , b){
return a - b;
}), '보너스' , 보너스);
// 이렇게 a - b 로 하면 오름차순으로 정렬이 되고
// b - a 로하면 내림차순으로 정렬이된다.
//sort 알고리즘은 이렇게 된다
*아래 내용은 오름차순이다!!!!!!
만약 sort(function(a,b){
return a- b;
})
소트함수가 있고
이렇게 a b가 있고
a 빼기 b이면
여기서 만약 주어진 숫자배열이 [7,3,4,8,9,12]
이렇게 있다 치면
이 배열을 서로 비교를 하는건데 어떻게 비교하냐면
먼저
a 가 7 이고
b 가 3 이다
이런식으로 비교를 하는데
그럼
a 빼기 b니까
7 - 3 이면 4가 나오잖아
그래서
이 결과값 이 4가되는거고
이 결과값 4가 0보다 크면 자리를 바꾸는거다
즉 여기서는 0보다 큰값이 결과값으로 나오게되면 자리를 바꾼다 가 바로 sort이다
그래서
[7,3,4,8,9,12]
에서
[3,7,4,8,9,12]
이렇게 바꾸고
그다음에는
7 - 4 이렇게 가는거다
그럼 결과값 3 이니까 0보다 크니까
자리를 바꾸면
[3,4,7,8,9,12]
이렇게 되고
또
그담에
7 - 8 이니까 결과값 -1 이나오니까 0 보다 작으니까 이번에는 자리를 바꾸지않는다
또
그다음 순서는
8 - 9 = -1
이니까 안바꾸고
그담
9 - 12 = -3 이니까
안바꾸고
이번엔 내림차순으로 정리를 하는 방법이다
내용은 비슷한데
sort(function(a,b){
return b - a;
})
이번에는 b - a 라고 한다면 (이게 내림차순인데)
[7,3,4,8,9,12]
이런배열을 내림차순으로 정리를하면
3 -7 = -4 가 되니까 0보다 작으니까 순서가 바뀌지 않는다
(이제는 0보다 크면 순서가 바뀌는거다)
[7,3,4,8,9,12] 똑같고
그리고
4 - 3 = 1 이면 0보다 크니까 순서가 바뀐다
[7,4,8,3,9,12]
그리고
8 - 3 = 4 니까 0보다 크니까 순서가 바뀌고
[7,4,8,9,3,12]
이런식으로
계속
[7,4,8,9,12,3]
이렇게
또 비교를해서
[12,9,8,7,4,3]
-숫자뿐만이 아니라 문자도 서로 정렬이 가능하다(문자에 숫자를부여해서 비교를해서 바꾼다던가..)
======================
여기까지 전체 소스
<div id="결과창">결과창</div>
<div class="보너스">보너스</div>
<div class="보너스"></div>
<div class="보너스"></div>
<div class="보너스"></div>
<div class="보너스"></div>
<script src="lotto.js">
</script>
=======================
var 후보군 = Array(45)
.fill()
.map(function(요소,인덱스){
return 인덱스 + 1;
});
console.log(후보군);
var 셔플 = [];
while (후보군.length > 0 ){
var 이동값 = 후보군.splice(Math.floor(Math.random() * 후보군.length) , 1 )[0];
셔플.push(이동값);
}
console.log(셔플);
var 보너스 = 셔플[셔플.length - 1];
var 당첨숫자들 = 셔플.slice(0 , 6);
console.log('당첨숫자들',당첨숫자들.sort(function(a , b){
return a - b;
}), '보너스' , 보너스);
var 결과창 = document.getElementById('결과창');
for(var i = 0;i < 당첨숫자들.length;i += 1){
var 공 = document.createElement('div');
공.textContent = 당첨숫자들[i];
결과창.appendChild(공);
}
// var 공 = document.createElement('div');
// 공.textContent = 보너스;
// 결과창.appendChild(공);
var 보너스칸 = document.getElementsByClassName('보너스')[0]; //여기서 클래스에만 [0]을 붙이는 이유는 아이디는 한번만쓸수있는데, 클래스는 여러번 쓸수있기떄문에 식별을위해서 [0] 이런식으로 번호를 찾아주어야한다
var 보너스공 = document.createElement('div');
보너스공.textContent = 보너스;
보너스칸.appendChild(보너스공);
이어서
1초에 한번씩 공을 보여주는 (긴장감같은 거를 조성하기위해) 기능을 추가해보자!
자~코드로돌아가서
1초뒤에 뭐가 하고싶다 2초뒤에 뭔가 하고싶다를 어떻게 할까?
뭔가 클릭을 했을때 2초뒤에 뭔가를 실행하고싶은거
이런걸 비동기라고 한다
비동기는 순서대로 실행되지않게 하는것
그것은 settimeout 이라는게 있다
콜백함수도 맞다
저 for문 안에 콜백함수를 추가해주면 된다
for(var i = 0;i < 당첨숫자들.length;i += 1){
var 공 = document.createElement('div');
공.textContent = 당첨숫자들[i];
결과창.appendChild(공);
}
여기서 이렇게 코드추가~
for(var i = 0;i < 당첨숫자들.length;i += 1){
var 공 = document.createElement('div');
공.textContent = 당첨숫자들[i];
결과창.appendChild(공);
}
그래서 셋타임함수 추가하면
for(var i = 0;i < 당첨숫자들.length;i += 1){
setTimeout(function 비동기콜백함수(){
var 공 = document.createElement('div');
공.textContent = 당첨숫자들[i];
결과창.appendChild(공);
}, 1000); // 밀리초
}
==============================
근데 여기서 클로져 문제가 있어서 클로져 문제를 해결해야된다.
셋타임 함수는 큐에서 늦게 나와서 그때는 값이 없다?안찍히는거다
그럼 구식 방법으로 하자면
for문을 쓰지않고 그냥 무식하게 가는거다
그냥 6번 다 코드로 찍는방법이다...
setTimeout(function 비동기콜백함수(){
var 공 = document.createElement('div');
공.textContent = 당첨숫자들[0]; // i를 0 으로
결과창.appendChild(공);
}, 1000); // 1 밀리초
setTimeout(function 비동기콜백함수(){
var 공 = document.createElement('div');
공.textContent = 당첨숫자들[1]; // i를 1 으로
결과창.appendChild(공);
}, 2000); // 2 밀리초
setTimeout(function 비동기콜백함수(){
var 공 = document.createElement('div');
공.textContent = 당첨숫자들[2]; // i를 2 으로
결과창.appendChild(공);
}, 3000); // 3밀리초
setTimeout(function 비동기콜백함수(){
var 공 = document.createElement('div');
공.textContent = 당첨숫자들[3]; // i를 3 으로
결과창.appendChild(공);
}, 4000); //4 밀리초
setTimeout(function 비동기콜백함수(){
var 공 = document.createElement('div');
공.textContent = 당첨숫자들[4]; // i를 4 으로
결과창.appendChild(공);
}, 5000); //5 밀리초
setTimeout(function 비동기콜백함수(){
var 공 = document.createElement('div');
공.textContent = 당첨숫자들[5]; // i를 5으로
결과창.appendChild(공);
}, 6000); // 6밀리초
이렇게 일일이 찍어주면 6개가 나온다
그리고 밑에 보너스칸도 셋타임함수 적용
setTimeout(function 비동기콜백함수(){
var 보너스칸 = document.getElementsByClassName('보너스')[0];
var 보너스공 = document.createElement('div');
보너스공.textContent = 보너스;
보너스칸.appendChild(보너스공);
} , 7000); // 7초
==========================
TIP >
html 에서 쓰던걸 자바스크립트에서 똑같이 쓸수없다
예를들어
html css 작성법은border-radius 인데
자바스크립트에서는 - 이게 마이너스로 인식해서
그리고
html에서 id는
자바스크립트에서
공.id =
이렇게 id는 그냥 쓸수있고,
html 에서 class는
자바스크립트에서
class 이렇게 못쓴다
공.className =
이렇게 클래스네임으로 써야 자바스크립트에서 알아먹는다.
그래서
자바스크립트에서 클래스 가져올때
document.getElementsByClassName();
이렇게 클래스네임으로 쓰는 이유다.
(겟엘리먼츠 꼭 s를 붙여야함, 겟엘리먼트바이아이디는 걍 s가 없음 , 그래서 요즘은 쿼리 셀렉터를 많이 사용함!!)
font-size 이것도
이렇게
공.style.fontSize = '12px';
이렇게 바꿔서 쓴다
=============================
마지막 전체 코드 수정후>>>>>>>>>>
==========================
Document<div id="결과창">당첨숫자</div>
<div class="보너스">보너스!</div>
<div class="보너스"></div>
<div class="보너스"></div>
<div class="보너스"></div>
<div class="보너스"></div>
<script src="lotto.js">
</script>
=================================
var 후보군 = Array(45)
.fill()
.map(function(요소,인덱스){
return 인덱스 + 1;
});
console.log(후보군);
var 셔플 = [];
while (후보군.length > 0 ){
var 이동값 = 후보군.splice(Math.floor(Math.random() * 후보군.length) , 1 )[0];
셔플.push(이동값);
}
console.log(셔플);
var 보너스 = 셔플[셔플.length - 1];
var 당첨숫자들 = 셔플.slice(0 , 6);
console.log('당첨숫자들',당첨숫자들.sort(function(a , b){
return a - b;
}), '보너스' , 보너스);
// for(var i = 0;i < 당첨숫자들.length;i += 1){ // for문은 여기선 클로져 문제때매 안쓰고 중급시간에 다시 강의!!!
// setTimeout(function 비동기콜백함수(){
// var 공 = document.createElement('div');
// 공.textContent = 당첨숫자들[i];
// 결과창.appendChild(공);
// }, 1000); //밀리초 1000밀리초는 1초임!
// }
// var 공 = document.createElement('div');
// 공.textContent = 보너스;
// 결과창.appendChild(공);
var 결과창 = document.querySelector('#결과창');
function 공색칠하기 (숫자 , 결과창){
var 공 = document.createElement('div');
공.textContent = 숫자;
공.style.display = 'inline-block';
공.style.border = '1px solid black';
공.style.borderRadius = '10px';
공.style.width = '20px';
공.style.height = '20px';
공.style.textAlign = 'center';
공.style.marginRight = '10px';
//공.id = '공아이디' + 숫자; // 이렇게 아이디로 할수도있고
공.className = '공아이디' + 숫자; // 클래스로 할수도 있음
공.style.fontSize = '12px';
var 배경색;
if(숫자 <= 10){
배경색 = 'red';
}else if(숫자 <= 20) {
배경색 = 'orange';
}else if(숫자 <= 30){
배경색 = 'yellow';
}else if(숫자 <= 40){
배경색 = 'blue';
}else{
배경색 = 'green';
}
공.style.background = 배경색;
결과창.appendChild(공);
}
//이 아랫부분 코드수정//
// 클로져 적용//
//수정된 코드 (클로져 적용한 코드임)
for(var i = 0 ; i < 당첨숫자들.length ; i++){
(function 클로져(j){
setTimeout(function (){
공색칠하기(당첨숫자들[j], 결과창);
}, (j + 1) * 1000);
})(i);
};
setTimeout(function 비동기콜백함수(){
공색칠하기(당첨숫자들[0], 결과창);
}, 1000);
setTimeout(function 비동기콜백함수(){
공색칠하기(당첨숫자들[1], 결과창);
}, 2000);
setTimeout(function 비동기콜백함수(){
공색칠하기(당첨숫자들[2], 결과창);
}, 3000);
setTimeout(function 비동기콜백함수(){
공색칠하기(당첨숫자들[3], 결과창);
}, 4000);
setTimeout(function 비동기콜백함수(){
공색칠하기(당첨숫자들[4], 결과창);
}, 5000);
setTimeout(function 비동기콜백함수(){
공색칠하기(당첨숫자들[5], 결과창);
}, 6000);
setTimeout(function(){
var 칸 = document.querySelector('.보너스'); //여기서 클래스에만 [0]을 붙이는 이유는 아이디는 한번만쓸수있는데, 클래스는 여러번 쓸수있기떄문에 식별을위해서 [0] 이런식으로 번호를 찾아주어야한다
공색칠하기(보너스,칸); // 여기 추가
} , 7000);
수정된 부분은
css처리를 하는부분이고
이제 , 색깔입히는작업이랑
중복된 부분 함수로 넣고 처리하기 이정도이다.
css 작업을 자바스크립트 안에서 처리할때 하는 코드랑
중복 코드를 함수안에 넣어서 코드량 을 줄이는 부분이 추가가 되었는데
이부분은
공색 칠하기 라는 함수를 하나 만들어서
그안에 중복코드를 넣고
(css부분 포함)
바뀌는 부분은 매개변수로 처리해서 넘겨주게만들어놓고
또 보너스부분도 같이 함께 처리해서
수정한 사항이다.
보너스부분을 설명하자면
칸 변수는 보너스를 가져와서 칸에 저장된거고
공색칠하기 함수를 적용하면
매개변수에 보너스랑 , 칸 을 넣는 이유는
보너스는 매개변수로 넘어가면
화면에 보너스로 처리된 숫자가 뿌려지는 부분이고
공.textContent 해서 , 공에 저장이되고,
이제
칸은 매개변수로 넘어가면 , 결과창으로 넘어가서
결과창.appendChild(공);
이 부분으로 처리되면서
최종적으로 화면에 부려지는부분으로 공이 매개변수로 또 들어가서 최종적으로 보너스 숫자가 화면에 뿌려지게된다.
그리고
디자인이적용되고, 보너스부분 숫자가 나온다
그리고 숫자 별로 컬러가 입혀지는 코드는
if문으로 처리해서
일단 배경색이라는 변수를 하나만들어서 배경색이라는 변수안에 컬러가 들어가면~
10보다 작은수는 red
20보다 작은수 orange
30보다 작은수 yellow
등등
이렇게 해서
이 색깔의 값이 공.style.background 로 저장이되면
공의 색깔이 최종적으로 적용이 되며
역시나 어펜드차일드를 통해 화면에 뿌려지는 그런 과정이다.
그리고 왠맨하면 자바스크립트에서 css나 html 엘리먼트를 정의하지말고
html 이나 css 단에서 정의해라
이런식으로
공.className = '공아이디' + 숫자; // 클래스로 할수도 있음 // 그리고 사실 자바스크립트에서 정의하지말고 css파일안에서 정의하는게 좋다
// 공.className = '공'; 이렇게 말이다. 이렇게해놓고 html로 가서 정의한다.