728x90
반응형
1) Javascript 복습
1-1) 클로저
1-2) 로또 Refactoring
1) Javascript 복습
1-1) 클로저
function main() {
for (var i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 1000 * i);
}
}
main();
// 문제
// var 키워드는 "함수 레벨 스코프"이므로
// main 함수 바로 밑(for 문 바로 위)에 "var i;"로 선언이 되고,
// setTimeout()의 경우, 본인 스코프(for 문 내부) 내에서는 변수 i를 찾을 수 없기에
// for 문 위로 올라와 변수 i를 찾게 되는데
// 이때 변수 i는 이미 for 문을 다 돈 상태이기에 결과적으로 "i = 5"의 값을 가지고 있는 상태이다!
// 따라서 결국 콘솔에는 setTimeout()에서 지정한 시간 간격을 두고 5가 5번 찍히게 된다!!
위의 코드 문제를 해결하는 방법
- var를 let 키워드로 바꾸면 됨!!
- 즉시실행함수로 실행시키면 됨!!
// 1. var를 let 키워드로 바꾸면 됨!!
function main() {
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, 1000 * i);
}
}
main();
// 2. 즉시실행함수로 실행시키면 됨!!
// 즉시실행함수 형태
// 1) 즉시실행함수(arrow function 버전)
(() => {
console.log("asdf");
})();
// 2) 즉시실행함수(함수 선언문 버전)
(function () {
console.log("asdf");
})();
// 해결
function main() {
for (var i = 0; i < 5; i++) {
((j) => {
setTimeout(() => {
console.log(j);
}, 1000 * j);
})(i);
}
}
main();
실행 컨텍스트, 스코프, 이벤트 루프를 이해해야 "클로저"를 정확히 이해할 수 있다!!
// 클로저 : 특정 함수의 return 값이 함수(고차함수 형태)일 때 상위 함수의 변수를 하위 함수에서 그대로 사용할 수 있는 것을 말한다!!
// 클로저 예시
function a() {
let txt = "hello world!!";
return () => {
console.log(txt);
};
}
const point = a();
console.log(point);
/*
// point 변수를 콘솔에 출력할 시 a 함수를 실행시킨 결과(return 값)인 아래의 화살표 함수 그 자체가 찍힌다!
() => {
console.log(txt);
};
*/
console.log(point()); // hello world!!
const area = document.querySelector('#areaID'); // 코드 작업을 위해 임의로 해당 id를 가진 element가 있다고 가정함!!
const clickHandler = (i) => {
const num = i + 1;
return (e) => {
console.log(num);
};
};
area.addEventListener("click", clickHandler());
function inner() {
let count = 0;
function outer() {
count++;
return count;
}
return outer;
}
const counter = inner(); // outer 함수 자체가 counter 변수에 들어감!!
counter();
counter();
counter();
const a = counter();
console.log(a); // result: 4
// Counter 함수를 함수 표현식으로 선언함!!
const Counter = (type) => {
// 매개변수가 "type"이다!!
let count = 0; // Counter 함수 안에서 "count"라는 변수를 선언함!
const increment = () => ++count; // Counter 함수 안에 있는 const 변수를 증가시키는 increment 변수 선언
const decrement = () => --count; // Counter 함수 안에 있는 const 변수를 감소시키는 decrement 변수 선언
return type === "increment" ? increment : decrement;
/*
// 바로 위의 삼항 연산자 구문과 동일한 if 문
if (type === "increment") {
return increment;
} else {
return decrement;
}
*/
};
const increment = Counter("increment"); // () => ++count
const decrement = Counter("decrement"); // () => --count
increment(); // 1
increment(); // 2
increment(); // 3
decrement(); // -1
decrement(); // -2
const result = increment(); // 4
console.log(result); // 4
// Counter 함수의 다른 예시
const Counter = (type) => {
let count = 0;
return [() => ++count, () => --count];
};
const [increment, decrement] = Counter();
/*
// 바로 위의 배열 구조분해할당 구문과 동일한 코드
const CounterFn = Counter(); // Array [() => {}, () => {}]
const incre = CounterFn[0];
const decre = CounterFn[1];
*/
increment(); // 1
increment(); // 2
increment(); // 3
decrement(); // 2
decrement(); // 1
const result = increment(); // 2
console.log(result); // 2
// 바로 위의 Counter 함수의 return 값을 객체로 표현한 경우
const Counter = (type) => {
let count = 0;
return {
increment: () => ++count,
decrement: () => --count,
}
};
const {increment, decrement} = Counter();
/*
// 바로 위의 객체 구조분해할당 구문과 동일한 코드
const CounterFn = Counter(); // Object {increment: () => {}, decrement: () => {}}
const incre = CounterFn['increment'];
const decre = CounterFn['decrement'];
*/
increment(); // 1
increment(); // 2
increment(); // 3
decrement(); // 2
decrement(); // 1
const result = increment(); // 2
console.log(result); // 2
함수 선언 시 만일 매개변수가 3개 이상이라면 객체로 받는 것이 좋다!!
일반함수를 사용하려는 경우에는 function 키워드 대신 arrow function을 쓰는 것이 좋다!!
const a = 10;
const add10 = (a) => a + 10;
console.log(add10(a)); // 20
// 고차함수는 아래와 같이 arrow function으로 표현하기 좋다!!
const f1 = () => () => 1;
// 예시 코드
const f2 = () => {
let count = 0;
return [() => ++count, () => --count];
};
// 바로 위의 예시 코드를 arrow function을 사용하여 변환한 코드
const f2 = (count) => [() => ++count, () => --count];
const Counter = f2(0);
console.log(Counter[0]()); // 1
console.log(Counter[0]()); // 2
console.log(Counter[1]()); // 1
console.log(Counter[0]()); // 2
console.log(Counter[0]()); // 3
// 바로 위의 arrow function 코드에서 count 변수의 초기값을 지정해준 코드 버전
const f2 = (count = 0) => [() => ++count, () => --count];
// (중요!!) Javascript 메커니즘 중 "함수는 값이다"라는 사실을 꼭 명심할 것!!
/*
function inner() {
let count = 0;
function outer() {
count++;
return count;
}
return outer;
}
*/
// 바로 위의 inner 함수를 arrow function을 사용해 변환한 코드
const make = (count) => () => ++count;
1-2) 로또 Refactoring
lotto.js(1 ~ 45개의 로또번호 중 랜덤으로 뽑은 6개의 숫자 배열과 해당 배열의 각 요소별 구간 나누기까지 구현)
const getNumber = (start, end) => {
// if (end < start) return null;
// return Math.floor(Math.random() * (end - start) + start) + 1;
// 바로 위의 코드를 좀 더 간단히 refactoring한 코드
const random = Math.floor(Math.random() * (end - start) + start);
return end < start ? null : random;
};
const randomLotto = (length, count) => {
// TODO : 1 ~ 45까지의 내용 만들기
// TODO : 45개짜리 배열 생성 후 이 중 6개를 뽑아야 함!
// TODO : Math.random 메서드를 활용해서 내용을 뽑기
const result = new Array(count).fill(null);
const lotto = new Array(length).fill(null).map((value, index) => index + 1);
return result
.map((v) => {
// index를 뽑는 변수
const lottoIndex = getNumber(1, lotto.length);
// lotto 배열에서 lottoIndex의 인덱스 값의 요소를 뽑고, 배열에서도 제거
const [number] = lotto.splice(lottoIndex, 1);
return number;
})
.sort((a, b) => a - b);
};
const between = (number) => Math.ceil(number / 10) - 1;
const classPattern = {
0: "a",
1: "b",
2: "c",
3: "d",
4: "e",
};
// for (const value in lotto) {
// console.log(getClassName[between(lotto[value])]);
// }
const getClassName = (arr) => arr.map((v) => classPattern[between(v)]);
const lottoArray = randomLotto(45, 6);
console.log(lottoArray);
console.log(getClassName(lottoArray));
lotto.js(클로저를 활용한 Refactoring 버전)
const getLotto = ({ totalNumber, count }) => {
const result = new Array(count).fill(null);
const lotto = new Array(totalNumber)
.fill(null)
.map((value, index) => index + 1);
const ClassPattern = {
0: "a",
1: "b",
2: "c",
3: "d",
4: "e",
};
const getNumber = (start, end) => {
const random = Math.floor(Math.random() * (end - start) + start);
return end < start ? null : random;
};
const getSpliceNumber = (arr) => (v) => {
const lottoIndex = getNumber(1, arr.length);
const [number] = arr.splice(lottoIndex, 1);
return number;
};
const randomLotto = () =>
result.map(getSpliceNumber(lotto)).sort((a, b) => a - b);
const between = (number) => Math.ceil(number / 10) - 1;
const getClassName = (arr) => arr.map((v) => ClassPattern[between(v)]);
const lottoArr = randomLotto();
return {
lotto: lottoArr,
className: getClassName(lottoArr),
};
// console.log(lottoArray)
// console.log(getClassName(lottoArray))
};
const config = {
totalNumber: 45,
count: 6,
};
const { className, lotto: lottoArr } = getLotto(config);
console.log(className, lottoArr);
'Javascript > Javascript(2022 version)' 카테고리의 다른 글
Javascript 기초(8) - callback hell, Promise, async/await (0) | 2022.12.21 |
---|---|
Javascript 복습 - 스코프, 호이스팅, function 키워드, this binding (0) | 2022.12.15 |
Javascript 기초(7) - 함수, 콜스택, 스코프 체인, this (0) | 2022.11.26 |
Javascript 기초(6) - 상속 및 메서드 (0) | 2022.11.04 |
Javascript 기초(5) - 객체 및 메서드 (0) | 2022.11.03 |