📕 오늘의 책 '러닝 자바스크립트'
✨ one-day, one-chapter
📑 CHAPTER.4
반복 작업을 효율적으로 자동화하고 변화하는 조건에 대응 하기 위한 챕터
while 조건 을 만족하는 동안 코드를 계속 반복한다
let funds = 50
while(funds > 1 && funds < 100){
// 100을 보다 낮고, 1보다 높으면 반복 실행
// 네버엔딩 무한 반복중..
}
블록 문block statement 제어문은 아니지만 제어문과 함께 사용한다. (복합문 compound statement 라고도 한다)
블록 문은 문 statement 여러 개를 중괄호로 묶은 것이며 자바스크립는 이들을 하나의 단위로 취급한다. 제어문 없이 블록 문만 써도 되지만 별 의미는 없다.
블록 문이 유용해지는 것은 제어문과 함꼐 쓸 때 이다. 예를 들어서 위의 while문에서 실행하는 루프는 블록문 전체를 실행한 후 조건을 다시 테스트한다.
let funds = 50
while(funds > 1 && funds < 100){
funds = funds + 2
funds = funds - 1
// 100번 실행하고 끝남
}
제어문제은 블록을 쓰는 것이 일반적이지만 생략도 가능하다.
let funds = 50
while(funds > 1 && funds < 100) funds = funds + 2;
대부분의 경우 자바스크립는 줄바꿈 문자를 포함해, 추가 공백을 신경 쓰지 않는다.
스페이스 하나는 스페이스 10개나 마찬가지고, 스페이스 10개나 빈 줄 10개나 마찬가지이다.
그렇다고 공백을 아무렇게나 쓰라는 말은 아니다.
아래의 예시 처럼 사용하게 되면 두 문 사이에 어떤 연관이 있다는 느낌을 주지 않고, 오해의 소지가 다분하기 때문에 피해야 한다.
let funds = 50
while(funds > 1 && funds < 100)
funds = funds + 2
조금 더 옳거나 흔히 쓰는 방식
let funds = 50
while(funds > 1 && funds < 100) funds = funds + 2;
while(funds > 1 && funds < 100) {funds = funds + 2;}
자바스크립트 자체가 오해할만한 코드
let funds = 50
while(funds > 1 && funds < 100)
funds = funds + 2; // 여기서 while까지의 바디(실행문)으로 인식
funds = funds - 1; // while이 다 끝나고 밖에서 실행
이렇게는 쓰지 말자!! 블록문과 블록이 없는 문을 섞어 쓰지 말자!
let funds = 50
if(funds > 1) {
//실행문
} else // 실행문2
if(funds > 1)
// 실행문
else { // 실행문2 }
//와 예시만 봐도 아찔하다 코드보다가 멘붕 올 듯..
시작하면서 조건을 검사하지 않고 일단 실행하고, 마지막에 검사한다.
do...while 루프는 루프 바디를 최소 1번은 실행하려 할 때 사용한다.
while 루프의 조건이 거짓 같은 값으로 시작하면 루프 바디는 한번도 실행되지 않는다.
let remaining = 3;
do{
// 실행문
}while (remainig > 0)
while, do while문을 for문으로 다 바꿔 쓸 수 있을 정도로 유연하지만,
for문에 가장 어울리는 작업은 따로 있다.
어떤 일을 정해진 숫자만큼 반복 할 때, 특히 그 일을 지금 몇 번째 하는 지 알아야할 때 사용한다.
const hand = [];
for(let roll=0; roll<3; roll++){
hand.push(roll*1)
}
// let roll = 0 (초기화) - 인덱스값의 초기값을 설정(roll은 변수이기때문에 무엇으로 설정하든 상관없다)
// roll<3 (조건) - 얼만큼 반복문을 돌릴 지 정한다 이경우 0, 1, 2 까지 총 3번 돌겠군요.
// roll++ (표현식)
if...else문과 if문의 차이, if...else문에서는 모든 분기가 행동으로 연결되어있지만 if 문에서는 분기 중 하나만 행동으로 연결됩니다.
// m 이상 n 이하의 무작위 정수를 반환
function rand(m,n){
return m + Math.floor((n - m + 1)*Math.random());
}
function randFace(){
return ["crown", "achor","heart", "spade", "club", "diamond"][rand(0,5)]
}
let funds = 50; // 시작조건
let round = 0;
while(funds > 1 && funds < 100){
round++;
let bets = {crown : 0, anchor : 0, heart : 0, spade : 0, club : 0, diamond: 0};
let totalBet = rand(1,funds);
if(totalBet===7){
totaBet = funds;
bets.heart = totalBet
}else {
let remaining = totalBet;
do{
let bet = rand(1, remaining);
let face = randFace();
bets[face] = bets[face] + bet;
remaining = remaining - bet;
} while (remaining > 0)
}
funds = funds - totalBet;
const hand = [];
for(let roll=0; roll<3; roll++){
hand.push(randFace());
}
let winnings = 0;
for (let die = 0; die < hand.length; die++){
let face = hand[die];
if(bets[face]> 0) winnings = winnings + bets[face];
}
funds = funds + winnings;
console.log(`\twiinings : ${winnings}`);
}
제어문의 일반적인 실행 방식을 바꾸는 네가지 문
1. break - 루프 중간에 빠져나가기
2. continue - 루프에서 다음 단계로 바로 건너뛰기
3. return - 제어문을 무시하고 현재 함수를 즉지 빠져나가기
4. throw - 예외 핸들러에서 반드시 처리해야 할 예외를 일으킴. 현재 제어문 바깥에 있어도 무방
if...else보다 다양한 조건으로 가능. 조건을 값으로 평가할 수 있는 표현식 이다.
return은 즉시 함수를 빠져나가므로 break문 대신 사용 할 수 있다.
(react에서 reducer 작업할 떄 보면 break보다 return을 주로 쓴다. 약간 이런거 참고하면 좋을 듯?)
switch(expression){
case value1 :
// expression을 평가한 결과가 value1 일 때 실헹
// ex : expression의 "type1"(value1) 일 경우 "type1" 로 case를 지정 하면 true일 때 실행됨
break; //break가 없을 경우 계속 실행된다
case value2:
case value3:
// 값 설정도 가능, 이 경우 2,3,4 모두 실행 됨.
case value4:
// value 2~4 모두 해당 바디 실행
break
default :
// expression의 평가값이 아에 없을 경우 디폴트 값 실행
break // 또는 retrun
}
객체의 프로퍼티 에 루프를 실행하도록 설계된 루프이다.
객체는 순서가 정해져있는 타입이 아니기때문에(array나 json와 같은 순서가 있는 것과는 다름) 브라우저를 실행할때마다 순서가 바뀔수도 있다. 중요한 건, for-in문을 순서대로 사용하고 싶다면 원하는 값을 얻을 수 없기 때문에 약간의 가공이 필요하다.
추가적으로 객체(object) 내장 메서드를 조금 공부해두자.
const player = {name : 'Thomas', rank:'Midshipman', age: 25};
for(let prop in player){
if(!player.hasOwnProperty(prop)) continue;
console.log(prop + ': ' + player[prop]);
}
ES6에 새로 생긴 반복문, 컬렉션의 요소에 루프를 실행하는 문법인데,
배열은 물론 이터러블(iterable)객체에 모두 사용할 수 있는 범용적인 루프이다.
배열에도 사용이 가능하지만 각 요소의 인덱스를 알아야 한다면 for을 사용하자.
const hand = [randFace(), randFace(), randFace()];
for(let i=0; i<hand.length; i++)
console.log(`Roll ${i+1} : ${hand[i]}`);
특정 조건이 맞을 때만 루프 바디를 실행해야 할 경우(제어문 중첩) countinue를 사용하여 간결하게 구조를 바꿀 수 있다.
while(funds > 1 && funds < 100) {
let totalBet = rand(1, funds);
if(totalBet === 13){
console.log("Unlucky! Skip this round....");
continue;
}
// body
}
break, return 모두 원하는 조건에 만족하면 더이상 루프문을 쓰지 않고 바로 루프 or 함수 빠져나온다. 불필요한 루프를 돌아서 성능을 저하시키는 것을 방지 할 수 있다.
루프가 함수 안에 있다면 return 사용 가능(switch 포함)
let firstPrime = null;
for(let n of bigArratOfNumbers){
if(isPrime(n)){
firstPrime = 0;
break;
}
}
continue 일하면서 별로 써본 적이 없다.
근데 일하면서 배열이나 객체를 이용하여 루프문을 돌리는 경우가 굉장히 많기 때문에,
해당 부분은 다시 머리속에서 상기시키기 좋은 예시들이 많았던 것 같다.
책에서는 간단하게 카드 게임을 이용하여 예시를 만들어서 했는데, 좋은 예시였던 것 같다.