반복문

Created
April 15, 2024
Tags
JavaScript

JavaScript에서는 여러 가지 반복문을 제공하여 배열, 객체, 문자열 등의 데이터를 반복 처리할 수 있다. 이 문서에서는 JavaScript의 주요 반복문인 for, forEach, for...of, for...in, while에 대해 설명하고, forEachfor의 동기/비동기 처리 방법도 다룬다.

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문을 사용할 수 있지만 배열의 인덱스를 반복한다.
👈🏻 조건문
  함수 👉🏻