이번 장은 타이머 사용하기가 핵심 -> 정해진 시간 뒤에 특정 코드가 동작
저번 시간 map 메서드에 대한 복습
① 1 - 45까지의 숫자를 준비한다.
② 숫자를 섞는다.
③ 공 7개를 뽑는다. 마지막 공은 보너스 공이 된다.
④ 1초마다 공을 하나씩 화면에 표시한다.
⑤ 끝
따라서 첫번째 순서는 배웠던 map 메서드를 통해 공 45개를 만든다.
const candidate = Array(45).fill().map((v,i)=> i+1); // 1 - 45
나는 아래처럼 작성했는데 결괏값이 ...
const candidate = Array(45).fill().map((v, i) => i + 1);
let answer = [];
while (candidate.length > 0) {
const index = Math.floor((Math.random() * candidate.length)); // 0 - 44
let random = candidate.splice(index, 1);
answer.push(random);
}
console.log(answer);
이렇게 나왔다. 알고보니 splice 의 반환값은 배열이다. random 에 배열 45개를 담은 것이었다...
반환 값
제거한 요소를 담은 배열. 하나의 요소만 제거한 경우 길이가 1인 배열을 반환합니다. 아무 값도 제거하지 않았으면 빈 배열을 반환합니다.
그래서 아래처럼 작성해줘야 한다.
const candidate = Array(45).fill().map((v, i) => i + 1);
const shuffle = [];
while (candidate.length > 0) {
const random = Math.floor((Math.random() * candidate.length)); // 0 - 44
const spliceArray = candidate.splice(random, 1);
const value = spliceArray[0];
shuffle.push(value);
}
console.log(shuffle);
아무튼 이러한 알고리즘을 피셔-에이츠 셔플 이라고 부른다!
공 정렬하기
slice 메서드는 배열의 원본을 바꾸지 않는다. map 메서드도 같다.
이런 메서드들을 따로 외우는 것이 좋다.
splice 와 slice 메서드의 차이
splice 는 원본 배열을 수정해버리지만, slice 는 수정하지 않는다. splice 는 추가도 가능하지만 slice 는 잘라내는 것만 가능하다. 또한 slice(3, 5) 는 3, 5 둘 다 인덱스이다. (처음 인덱스, 끝 인덱스)... 다만 끝 인덱스는 포함하지 않는다.
array.slice(4, -1) 는 뭘까?
slice() 메서드는 어떤 배열의 begin부터 end까지(end 미포함) 에 대한 얕은 복사본을 새로운 배열 객체로 반환합니다. 원본 배열은 바뀌지 않습니다.
const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
console.log(animals.slice(2));
// expected output: Array ["camel", "duck", "elephant"]
console.log(animals.slice(2, 4));
// expected output: Array ["camel", "duck"]
console.log(animals.slice(1, 5));
// expected output: Array ["bison", "camel", "duck", "elephant"]
console.log(animals.slice(-2));
// expected output: Array ["duck", "elephant"]
console.log(animals.slice(2, -1));
// expected output: Array ["camel", "duck"]
이어서..
공 45개를 뽑았다. 현재 suffle 안에 들어 있는 순서가 뽑은 순서이다. 이를 오름차순으로 정렬하려면?
전체 숫자를 쭉 훑어보면서 가장 작은 숫자를 하나 가져오고, 다시 전체를 쭉 훑어보다가 그 다음 작은 숫자를 가져와야 한다. 이런식으로 숫자를 정렬하다보면 모든 숫자가 정렬되는데 이런 방식을 선택 정렬 알고리즘이라고 한다.
(더 효율적인 알고리즘이 존재)
여기선 자바스크립트가 제공하는 배열의 정렬 메서드를 사용한다.
자바스크립트는 정렬을 위한 sort 메서드를 제공한다. 배열의 크기가 커질수록 정렬의 효율이 선택 정렬보다 훨씬 좋아진다.
sort 메서드
sort() 메서드는 배열의 요소를 적절한 위치에 정렬한 후 그 배열을 반환합니다. 정렬은 stable sort 가 아닐 수 있습니다. 기본 정렬 순서는 문자열의 유니코드 코드 포인트를 따릅니다.
const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
console.log(months);
// expected output: Array ["Dec", "Feb", "Jan", "March"]
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);
// expected output: Array [1, 100000, 21, 30, 4]
구문
arr.sort([compareFunction])
매개변수
compareFunction Optional
정렬 순서를 정의하는 함수. 생략하면 배열은 각 요소의 문자열 변환에 따라 각 문자의 유니 코드 코드 포인트 값에 따라 정렬됩니다.
반환 값
정렬한 배열. 원 배열이 정렬되는 것에 유의하세요. 복사본이 만들어지는 것이 아닙니다.
설명
compareFunction이 제공되지 않으면 요소를 문자열로 변환하고 유니 코드 코드 포인트 순서로 문자열을 비교하여 정렬됩니다. 예를 들어 "바나나"는 "체리"앞에옵니다. 숫자 정렬에서는 9가 80보다 앞에 오지만 숫자는 문자열로 변환되기 때문에 "80"은 유니 코드 순서에서 "9"앞에옵니다.
compareFunction이 제공되면 배열 요소는 compare 함수의 반환 값에 따라 정렬됩니다. a와 b가 비교되는 두 요소라면,
- compareFunction(a, b)이 0보다 작은 경우 a를 b보다 낮은 색인으로 정렬합니다. 즉, a가 먼저옵니다.
sorting의 종류 - heap sort, quick sort, merse sort
2021.06.17 - [코테 연습] - 스터디 1일차
간단히 읽어보기!
array.slice().sort().sort((a, b) => a - b)
array.slice().sort().sort((a, b) => {return a - b}) // 둘은 같음. 참고
오름 차순 정렬 (a-b), 내림 차순(b-a)
그래서 선택 정렬은 unstable sort 구나..
슬라이스를 중간에 넣어두면 배열을 복사한 다음에 정렬하기 때문에 원본 배열은 바뀌지 않는다!
참고 문자열을 정렬할 때는 ...
arr.slice().sort((a, b) => a[0].charCodeAt() - b[0].charCodeAt()) // 오름 차순
캐릭터 코드로 바꾸는 메서드를 활용해야 한다.
1. space 32
2. 0(숫자) 48
3. A 65
4. a 97
근데 두번째 글짜까지 비교하려면..
arr.slice().sort((a, b) => a.localeCompare(b)) // 오름차순
arr.slice().sort((a, b) => b.localeCompare(a)) // 내림차순
일정 시간 후에 실행하기
setTimeout() => {
// 내용
}, 밀리초);
이때 setTimeout 안에 넣는 함수는 특정 작업(지정한 시간까지 기다리기) 이후에 후가로 실행되는 함수이므로, 콜백 함수라고 볼 수 있다.
두번째 인수가 밀리초 단위이므로 원하는 초에 1000을 곱해야 한다. 첫번째 인수로 넣은 함수는 지정한 밀리초 후에 실행된다.
setTimeout(() => {
const $ball = document.createElement('div');
$ball.className = 'ball';
$ball.textContent = winBalls[0];
$result.appendChild($ball);
}, 1000);
setTimeout(() => {
const $ball = document.createElement('div');
$ball.className = 'ball';
$ball.textContent = winBalls[1];
$result.appendChild($ball);
}, 2000);
중복을 제거해야 한다. -> (리팩토링화)
내가 생각한 코드
/* 중복 제거 */
function ballCreate() {
const $ball = document.createElement('div');
$ball.className = 'ball';
$result.appendChild($ball);
}
for (let i = 0; i < 6; i++) {
setTimeout(() => {
ballCreate();
$ball.textContent = winBalls[i];
},(i+1)*1000);
}
// 에러 발생: Uncaught ReferenceError: $ball is not defined
지역변수는 함수 내부에서 선언된 변수로, 함수가 실행되면 만들어지고 함수가 종료되면 소멸하는 변수입니다. 함수 외부에서는 접근할 수 없습니다. 그래서 안되는 거였나보다.
/* 중복 제거 */
const $result = document.querySelector('#result');
const $bonus = document.querySelector('#bonus');
function createBall(number, $target) {
const $ball = document.createElement('div');
$ball.className = 'ball';
$ball.textContent = number;
console.log(number);
$target.appendChild($ball);
}
for (let i = 0; i < 6; i++) {
setTimeout(() => { createBall(winBalls[i], $result) }, (i + 1) * 1000);
}
setTimeout(() => { createBall(bonus, $bonus) }, 7000);
15: 34
고차함수, 클로저 따로 정리
로또 추첨기를 만들어보고 느낀 점
이번엔 순서도를 만드는 건 어렵지 않았는데 코드로 구현하는 것이 어려웠다. Array, 원본 배열이 복사되는 slice, 함수를 작성하는 법, 클로저에 대한 개념 등등.. 정말 알아야 할게 많다고 느낀 6장이었다.
'🤹🏻♀️ Javascript' 카테고리의 다른 글
클래스, const 객체, 메서드, map 메서드 (0) | 2021.11.06 |
---|---|
제로초 자바스크립트 7장 (가위바위보) (0) | 2021.10.24 |
제로초 자바스크립트 5장 (숫자야구) (0) | 2021.10.18 |
제로초 자바스크립트 4장 (계산기) (0) | 2021.10.18 |
제로초 자바스크립트 3장 (쿵쿵따) (0) | 2021.10.15 |