자바스크립트 기초 #3 제어 흐름

#2 변수와 타입 에서 값을 다루는 도구를 봤습니다. 이번 글에서는 그 값들로 분기반복을 만드는 방법을 다룹니다.

if / else if / else #

가장 익숙한 분기.

if 기본
const score = 85;

if (score >= 90) {
  console.log('A');
} else if (score >= 80) {
  console.log('B');
} else if (score >= 70) {
  console.log('C');
} else {
  console.log('F');
}

조건은 truthy/falsy 검사가 됩니다. #2 에서 본 falsy 7가지(false, 0, -0, 0n, ‘’, null, undefined, NaN)면 else로 갑니다.

truthy 검사 관용구
const name = '커티스';

if (name) {
  // name이 비어있지 않은 문자열일 때
  console.log(`안녕, ${name}`);
}

// 거의 동일 — 명시적
if (name !== '') {
  console.log(`안녕, ${name}`);
}

짧고 의도가 분명할 때는 truthy 검사를, 무엇이 비어있는지 명확히 하고 싶을 때는 명시적 비교를. 둘 다 흔합니다.

삼항 연산자 — 짧은 분기에 적합한 표현 #

삼항 연산자
const score = 85;
const grade = score >= 60 ? '합격' : '불합격';
//             조건       ? 참일 때 : 거짓일 때

값을 정하는 위치(변수 할당, JSX, 객체 필드)에서 if/else보다 짧고 깔끔합니다. 다만 두 단계 이상 중첩하면 빠르게 읽기 어려워지니, 그럴 땐 if/else if로 풀어 쓰는 게 좋습니다.

whiledo...while #

조건이 참인 동안 반복합니다.

while
let count = 0;
while (count < 5) {
  console.log(count);
  count = count + 1;
}
// 0, 1, 2, 3, 4

do...while최소 한 번은 무조건 실행되는 변형. 사용자 입력처럼 “받아 보고 조건 검사” 인 경우에 적합합니다.

do...while
let answer;
do {
  answer = prompt('숫자를 입력하세요');
} while (isNaN(Number(answer)));

for — 클래식 루프 #

세 칸으로 구성됩니다 — 초기화 ; 조건 ; 매 반복 후.

고전 for
for (let i = 0; i < 5; i = i + 1) {
  console.log(i);
}
// 0, 1, 2, 3, 4

C/Java와 같은 모양을 다룹니다. 인덱스를 직접 다뤄야 할 때(역순, 건너뛰기, 두 배열 동시 진행)는 여전히 가장 명확합니다. 다만 일반 배열 순회는 for...of가 보통 더 읽기 좋습니다.

for...of — 배열 순회 표준 #

for...of — 모던 표준
const fruits = ['사과', '바나나', '포도'];

for (const fruit of fruits) {
  console.log(fruit);
}
// 사과, 바나나, 포도

배열의 을 하나씩 꺼내 줍니다. 인덱스가 필요 없으면 거의 항상 이쪽이 깔끔합니다.

인덱스도 함께 — entries() #

값과 인덱스 동시
const fruits = ['사과', '바나나', '포도'];

for (const [i, fruit] of fruits.entries()) {
  console.log(`${i}: ${fruit}`);
}
// 0: 사과, 1: 바나나, 2: 포도

fruits.entries()[인덱스, 값] 쌍을 만들어 주는 이터레이터. 디스트럭처링은 #5 객체와 배열에서 자세히 다룰 텐데, 일단은 “두 변수에 동시에 받는 문법"으로 기억하면 됩니다.

for...in — 거의 안 쓰는 변형 #

이름이 비슷해서 헷갈리는데, 객체의 키를 순회합니다. 배열에 쓰면 안 좋은 일이 자주 일어나요.

for...in (객체에)
const user = { id: 'u1', name: '커티스', age: 30 };

for (const key in user) {
  console.log(`${key}: ${user[key]}`);
}
// id: u1, name: 커티스, age: 30
for...in을 배열에 쓰면 사고
const arr = ['a', 'b', 'c'];
arr.foo = 'oops';

for (const key in arr) {
  console.log(key);
}
// 0, 1, 2, foo  ← foo도 나옴

배열의 인덱스(0, 1, 2) 와 함께 우리가 추가한 속성(foo)도 같이 들어옵니다. 그래서 배열은 절대 for...in으로 순회하지 않습니다. 객체는 Object.keys/values/entries를 쓰는 게 더 안전합니다.

객체 순회 — 권장 패턴
const user = { id: 'u1', name: '커티스', age: 30 };

for (const [key, value] of Object.entries(user)) {
  console.log(`${key}: ${value}`);
}

배열의 메서드 순회 — forEach, map, filter 미리보기 #

for...of 외에 배열은 함수형 스타일의 순회 메서드를 가집니다.

forEach / map / filter 미리보기
const numbers = [1, 2, 3, 4, 5];

// 부수효과만 — forEach
numbers.forEach((n) => console.log(n));

// 변환 — map
const doubled = numbers.map((n) => n * 2);
// [2, 4, 6, 8, 10]

// 거르기 — filter
const evens = numbers.filter((n) => n % 2 === 0);
// [2, 4]

이 메서드들은 #5 객체와 배열 에서 본격적으로 다룹니다. 지금은 “for 루프 외에도 표현 방법이 있다” 만 기억해 두세요.

breakcontinue #

루프 안에서 흐름을 제어하는 키워드는 두 가지입니다.

break — 루프 빠져나가기
for (let i = 0; i < 10; i = i + 1) {
  if (i === 5) break;
  console.log(i);
}
// 0, 1, 2, 3, 4
continue — 다음 반복으로
for (let i = 0; i < 5; i = i + 1) {
  if (i === 2) continue;
  console.log(i);
}
// 0, 1, 3, 4 (2 빠짐)

forEach/map/filter 같은 메서드 안에서는 break/continue가 동작하지 않습니다. 중간에 끊어야 하면 for...of로 다시 쓰거나 some/every 같은 메서드(다음 시리즈에서)를 씁니다.

switch — 여러 값 분기 #

switch 기본
const day = 'mon';

switch (day) {
  case 'mon':
  case 'tue':
  case 'wed':
  case 'thu':
  case 'fri':
    console.log('평일');
    break;
  case 'sat':
  case 'sun':
    console.log('주말');
    break;
  default:
    console.log('알 수 없음');
}

case는 위에서 아래로 검사되고, 일치하는 지점부터 break를 만날 때까지 계속 실행됩니다. 이게 흔히 함정이 되는 지점입니다 — break를 까먹으면 다음 case도 같이 실행됩니다(fallthrough).

break를 까먹은 사고
switch (day) {
  case 'mon':
    console.log('월요일!');
    // break 빠뜨림
  case 'tue':
    console.log('화요일!');
    break;
}
// day가 'mon'이면 — 월요일! 화요일! 둘 다 출력

switch 비교는 엄격(===) #

switch의 case 매칭은 항상 ===로 합니다. 자동 변환이 일어나지 않습니다.

엄격한 비교
switch (5) {
  case '5': console.log('a'); break;  // 일치 안 함
  case 5:   console.log('b'); break;  // 여기 매칭
}

이 점은 좋습니다 — ==의 함정에서 자유로워져요.

짧은 if의 함정 — 중괄호 생략 #

자바스크립트는 짧은 if에서 중괄호를 생략할 수 있습니다.

짧은 if — 위험
if (condition)
  doSomething();

문제는 두 줄 이상으로 늘어났을 때 사고가 납니다.

중괄호가 없으면 사고
if (condition)
  doSomething();
  alsoThis();    // 항상 실행됨 (if 와 무관)

들여쓰기는 if 안인 것처럼 보이지만 실제로는 항상 실행됩니다. 이런 사고를 막기 위해 짧은 if 라도 항상 중괄호를 쓰는 컨벤션이 안전합니다. ESLint의 curly 규칙이 정확히 이걸 강제합니다.

마무리 #

이번 글에서 정리한 내용:

  • if/else는 truthy/falsy 검사 또는 명시적 비교
  • 짧은 분기는 삼항 연산자, 그 이상은 if/else if
  • 일반 배열 순회는 for...of가 표준
  • for...in은 객체 키 순회 — 배열에는 쓰지 말기
  • break/continue는 일반 루프에서만, 메서드 콜백에서는 안 됨
  • switch는 fallthrough 주의, 비교는 항상 ===
  • 짧은 if 라도 중괄호 쓰는 게 안전

다음 글(#4 함수)에서는 자바스크립트의 함수 — 선언/표현식/화살표 세 가지 정의 방식, 매개변수 패턴, 그리고 호이스팅이 무엇인지 다룹니다.

X