JavaScript에서는 여러 가지 반복문을 제공하여 배열, 객체, 문자열 등의 데이터를 반복 처리할 수 있다. 이 문서에서는 JavaScript의 주요 반복문인 for
, forEach
, for...of
, for...in
, while
에 대해 설명하고, forEach
와 for
의 동기/비동기 처리 방법도 다룬다.
for
for
문. 길게 설명하지 않겠다. 초기화, 조건식, 증감식을 포함하여 특정 횟수만큼 반복한다.
for (initialization; condition; increment) {
// 실행할 코드
}
아래는 API를 호출하여 데이터를 가져오고, 그 데이터를 배열에 저장하는 코드이다.
const urls = [
'https://api.example.com/data1',
'https://api.example.com/data2',
'https://api.example.com/data3'
];
const fetchData = async (url) => {
const response = await fetch(url);
const data = await response.json();
return data;
};
const results = [];
const getAllData = async () => {
for (let i = 0; i < urls.length; i++) {
const data = await fetchData(urls[i]);
results.push(data);
}
console.log(results);
};
getAllData();
// 결과: 각 API 응답 데이터가 results 배열에 저장됨
forEach
forEach
메서드는 배열의 각 요소에 대해 제공된 콜백 함수를 한 번씩 실행하며, 그 실행 결과는 반환하지 않는다.
array.forEach(callback(currentValue, index, array), thisArg);
아래 예제에서 forEach
는 각 요소에 대해 콜백 함수를 실행하고, results
배열에 결과를 푸시한다. 하지만, forEach
자체는 아무런 값도 반환하지 않는다. (forEach
와 달리 map
메서드는 배열의 각 요소를 반환하여 새로운 배열을 반환한다.)
const numbers = [1, 2, 3, 4, 5];
const results = [];
numbers.forEach((number) => {
results.push(number * 2);
});
console.log(results); // 출력: [2, 4, 6, 8, 10]
forEach와 for의 동기/비동기 처리
forEach
는 비동기 작업을 기다리지 않고 바로 다음 코드를 실행한다.
Problem
여러 URL에서 데이터를 비동기로 가져와 dataResults
배열에 저장한 후 출력하려고 한다. 하지만 forEach
를 사용하면 비동기 작업이 완료되기 전에 배열을 출력할 수 있다.
let dataResults = [];
const urls = [
'https://jsonplaceholder.typicode.com/posts/1',
'https://jsonplaceholder.typicode.com/posts/2',
'https://jsonplaceholder.typicode.com/posts/3'
];
urls.forEach(async url => {
const response = await fetch(url);
const data = await response.json();
dataResults.push(data);
});
console.log(dataResults);
- 예상되는 결과는
[data1, data2, data3]
이지만, 비어 있는 배열이 출력된다. forEach
가 비동기 작업을 기다리지 않기 때문.
정리하자면,
forEach
는 배열 요소를 순차적으로 돌면서 콜백 함수를 실행할 뿐(동기), 콜백 함수가 끝날때 까지 기다렸다가 다음 콜백 함수를 실행하는 것이 아니라고 한다. 즉,forEach
자신이 실행하는 코드가 비동기를 하든 안 하든 관심이 없이 넘어간다는 것.
Solutions
for…of 반복문 사용
for...of
반복문을 사용하면 await
를 통해 비동기 작업을 순차적으로 처리할 수 있다. 하지만 이 방법은 forEach
를 사용했을 때와 달리 병렬로 처리되지 않는다.
let dataResults = [];
const urls = [
'https://jsonplaceholder.typicode.com/posts/1',
'https://jsonplaceholder.typicode.com/posts/2',
'https://jsonplaceholder.typicode.com/posts/3'
];
const fetchData = async () => {
for (const url of urls) {
const response = await fetch(url);
const data = await response.json();
dataResults.push(data);
}
console.log(dataResults); // 예상: [data1, data2, data3]
};
fetchData();
Promise.all() 사용
비동기 작업의 소요 시간이 크면 순차적으로 반복하는 대신 병렬 처리를 고려할 수 있다. 각 비동기 함수를 Promise
배열로 만들고, Promise.all
을 통해 실행하면 비동기 함수들을 동시에 실행할 수 있다. 이럴 때는 forEach
대신 map
을 사용할 수 있겠다.
let dataResults = [];
const urls = [
'https://jsonplaceholder.typicode.com/posts/1',
'https://jsonplaceholder.typicode.com/posts/2',
'https://jsonplaceholder.typicode.com/posts/3'
];
const fetchData = async () => {
const promises = urls.map(async url => {
const response = await fetch(url);
const data = await response.json();
return data;
});
dataResults = await Promise.all(promises);
console.log(dataResults); // 예상: [data1, data2, data3]
};
fetchData();
for…of
for...of
문은 반복 가능한 객체(예: 배열, 문자열, Map, Set 등)의 값을 반복할 수 있다.
for (const element of iterable) {
// 실행할 코드
}
예제
const numbers = [1, 2, 3, 4, 5];
// 배열의 각 요소를 두 배로 만들어 새로운 배열을 생성
const doubledNumbers = [];
for (const number of numbers) {
doubledNumbers.push(number * 2);
}
console.log(doubledNumbers); // 출력: [2, 4, 6, 8, 10]
이 예제는 배열 numbers
의 각 요소를 두 배로 만들어 새로운 배열 doubledNumbers
에 추가한다.
for…in
for...in
문은 객체의 속성을 반복적으로 순회하거나 열거하는 데 사용된다. 객체의 속성 이름(key)
을 가져와서 해당 속성에 대한 작업을 수행할 때 유용하다. 배열에도 사용할 수 있지만, 배열의 인덱스를 반복한다.
for (const property in object) {
// 실행할 코드
}
예제
const user = {
name: 'Alice',
age: 30,
occupation: 'Engineer'
};
// 객체의 속성을 반복하여 콘솔에 출력
for (const key in user) {
if (user.hasOwnProperty(key)) {
console.log(`${key}: ${user[key]}`);
}
}
// name: Alice
// age: 30
// occupation: Engineer
이 예제는 객체 user
의 속성 이름과 값을 반복하여 콘솔에 출력한다. 여기서 hasOwnProperty
메서드를 사용하여 객체 자체의 속성인지 확인하는 것이 중요하다. 이는 상속된 속성을 제외하고 객체의 고유 속성만 처리하기 위함이다.
while
while
문은 조건식이 참인 동안 코드를 반복해서 실행한다. 조건식이 처음부터 거짓이면, 한 번도 실행되지 않는다.
while (condition) {
// 실행할 코드
}
예제
let i = 0;
while (i < 5) {
console.log(i);
i++;
}
do…while
do...while
문은 조건식을 나중에 검사하므로, 최소한 한 번은 실행된다.
do {
// 실행할 코드
} while (condition);
예제
let i = 0;
do {
console.log(i);
i++;
} while (i < 5);
정리
for…in
문에서 변수로 선언되는 것은 객체의이름(key)
이다. JavaScript에서 배열도 객체이므로 당연히for…in
문을 사용할 수 있지만 배열의인덱스
를 반복한다.