for문은 어떤 로직을 반복해서 실행할 때 가장 흔히 쓰이는 문 중 하나예요.
JavaScript에서 for문은 for 키워드, 소괄호로 감싼 헤더, 그리고 중괄호로 감싼 루프의 _본문_을 담는 코드 블록으로 이루어져 있어요.
for (initialization; condition; step) {
// code that is executed repeatedly as long as the condition is
// true
}
초기화 부분에서는 보통 카운터 변수를 준비하고, 조건 부분에서는 루프를 계속할지 멈출지 검사하며, 단계 부분에서는 반복이 끝날 때마다 카운터를 증가시켜요. 헤더의 각 부분은 세미콜론으로 구분해요.
const list = ['a', 'b', 'c'];
for (let i = 0; i < list.length; i++) {
// code that should be executed for each item in the array
}
헤더의 세 부분은 모두 생략할 수 있어요. 실제로는 거의 쓰이지 않아요. 이에 대해서는 MDN 문서에서 더 자세히 읽어볼 수 있어요.
for문for문은 중첩해서 사용할 수 있어요. 예를 들어 중첩된 (다차원) 배열을 순회할 때 말이에요.
각 루프마다 서로 다른 카운터 변수를 만들어야 해요.
const coords = [
[1, 2],
[4, 7],
[10, -3],
];
for (let i = 0; i < coords.length; i++) {
for (let j = 0; j < coords[i].length; j++) {
// do something with coords[i][j]
}
}
루프 본문 안에서는 break 키워드로 루프 실행을 완전히 멈출 수 있어요.
반대로 continue 키워드는 현재 반복의 실행만 멈추고 다음 반복으로 넘어가요.
중첩 루프를 다룰 때 break와 continue는 기본적으로 항상 가장 안쪽 루프에 적용돼요.
레이블을 사용하면 이 동작을 바꿀 수 있어요.
레이블은 식별자 이름 뒤에 콜론을 붙인 형태로, 루프 앞에 (또는 위에) 놓아요.
이렇게 만든 레이블을 break나 continue와 함께 사용하면 그 문이 어느 루프에 적용될지 정할 수 있어요.
outer: for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
// ...
if (j > 5) {
continue outer;
}
// ...
}
}
비동기 코드를 다룰 때는 카운터 변수를 올바르게 선언하는 데 주의해야 해요.
1초를 기다린 뒤 setTimeout으로 카운터 변수를 비동기적으로 더하는 예제를 살펴볼까요.
카운터를 var로 선언하거나, let으로 선언하되 헤더 밖에서 선언하면 코드가 기대한 결과를 내지 않아요.
let sum = 0;
for (var i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// eventually sum will be 12 instead of 6 (1+2+3)
let sum = 0;
let i;
for (i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// same here, eventually sum will be 12 instead of 6 (1+2+3)
이 두 경우에 i는 특정한 루프 반복에만 속하지 않아요.
합이 계산될 때쯤이면 i는 이미 마지막 값인 4에 도달해 있어서, 합은 4 + 4 + 4 = 12가 돼요.
이 문제는 카운터를 헤더 안에서 let으로 선언하면 피할 수 있어요.
이렇게 선언하면 각 반복이 그 반복만의 변수 let i를 따로 갖게 돼요. 이 변수의 스코프는 루프 본문을 딱 한 번 실행할 때로 정확히 한정돼요.
그래서 나중에 합이 계산될 때, 각 콜백 함수는 아직 올바른 값을 담고 있는 자기 자신의 변수 i를 참조해요.
let sum = 0;
for (let i = 1; i < 4; i++) {
setTimeout(function () { sum += i; }, 1000);
}
// eventually sum will be 6 (1+2+3) as expected