JavaScript에서 반복을 위한 모범 사례

JavaScript에서 반복을 위한 모범 사례

이 기사에서는 JavaScript에서 반복을 위한 모범 사례를 설명합니다.

YouTube Video

JavaScript에서 반복을 위한 모범 사례

JavaScript에서는 반복을 위해 for 루프를 사용하는 것이 일반적입니다. 여기에서는 효율적이고 가독성 높은 코드를 작성하기 위해 for 루프를 사용하는 모범 사례를 자세히 설명합니다.

적합한 반복 구조 선택하기

JavaScript는 다양한 목적에 적합한 여러 반복 구조를 제공합니다.

 1// Example of a for loop
 2for (let i = 0; i < 5; i++) {
 3    console.log(i);
 4}
 5
 6// Example of a for...of loop
 7const array = [10, 20, 30];
 8for (const value of array) {
 9    console.log(value);
10}
11
12// Example of a for...in loop
13const obj = { a: 1, b: 2, c: 3 };
14for (const key in obj) {
15    console.log(`${key}: ${obj[key]}`);
16}
17
18// Example of a while loop
19let count = 0;
20while (count < 5) {
21    console.log(count);
22    count++;
23}
  • for은 반복 횟수가 미리 정해진 경우에 적합합니다.
  • for...of은 배열과 반복 가능한 객체를 간결하게 처리하는 데 적합합니다.
  • for...in은 객체의 속성을 반복 처리할 때 사용됩니다. 그러나 배열에는 적합하지 않습니다.
  • whiledo...while은 조건에 따라 반복문을 제어할 때 사용됩니다.

forEach 메서드와 for...of 문 활용하기

배열을 반복 처리할 때 for 문으로 인덱스에 접근하는 것이 일반적이지만, forEach 메서드나 for...of 문을 사용하는 것이 가독성이 더 좋을 수 있습니다.

 1// Using a standard for loop
 2const array = ["apple", "banana", "cherry"];
 3for (let i = 0; i < array.length; i++) {
 4    console.log(array[i]);
 5}
 6
 7// Using forEach
 8array.forEach(item => console.log(item));
 9
10// Using for...of
11for (const item of array) {
12    console.log(item);
13}
  • for은 반복 중 인덱스를 명시적으로 관리할 수 있습니다.
  • forEach 메서드는 콜백 함수를 사용하여 각 요소를 간결하게 처리합니다.
  • for...of은 가독성이 높으며 배열의 각 요소에 직접 접근할 수 있습니다.

루프 조건 최적화하기

루프 조건은 반복적으로 평가되므로 불필요한 계산을 피하면 성능을 향상시킬 수 있습니다.

 1const names = ["Alice", "Bob", "Charlie"];
 2const scores = [85, 92, 78];
 3
 4// Inefficient example
 5for (let i = 0; i < Math.min(names.length, scores.length); i++) {
 6    console.log(`${names[i]} scored ${scores[i]}`);
 7}
 8
 9// Efficient example
10for (let i = 0, len = Math.min(names.length, scores.length); i < len; i++) {
11    console.log(`${names[i]} scored ${scores[i]}`);
12}
  • 이 예에서 보여지는 것처럼, 계산 결과를 사전에 변수에 저장하면 더 효율적인 루프 실행이 가능합니다.
 1const scores = [85, 92, 78];
 2let sum = 0;
 3let sum2 = 0;
 4
 5// Inefficient example
 6for (let i = 0; i < scores.length; i++) {
 7    sum += scores[i];
 8}
 9console.log(`Total score : ${sum}`);
10
11// Efficient example
12for (let i = scores.length - 1; i >= 0; i--) {
13    sum2 += scores[i];
14}
15console.log(`Total score : ${sum2}`);
  • 이 예에서 보여지는 것처럼, 조건을 반대로 설정하는 것이 때로는 더 효율적일 수 있습니다.

루프 처리 최적화

루프 처리는 반복적으로 실행되므로, 불필요한 계산을 피하면 성능이 향상될 수 있습니다.

 1const array = ["apple", "banana", "cherry"];
 2
 3// Inefficient example
 4for (let i = 0; i < 100; i++) {
 5    const element = document.querySelector("#myElement");
 6    element.textContent = `Count: ${i}`;
 7}
 8
 9// Efficient example
10const element = document.querySelector("#myElement");
11for (let i = 0; i < 100; i++) {
12    element.textContent = `Count: ${i}`;
13}
  • 이 예제에서는 querySelector 메서드를 루프 바깥으로 이동시켜 불필요한 반복 계산을 제거합니다.

스코프를 신경쓰기

let 또는 const를 사용하여 루프 내부의 변수가 적절한 스코프를 가지도록 합니다. var는 함수 스코프에만 제한되므로 예상치 못한 동작이 발생할 수 있습니다.

 1// Using let
 2for (let i = 0; i < 3; i++) {
 3    console.log(i);
 4}
 5
 6// Potential issue with var
 7for (var i = 0; i < 3; i++) {
 8    setTimeout(() => console.log(i), 1000); // 3, 3, 3
 9}
10
11// Using let to avoid the issue
12for (let i = 0; i < 3; i++) {
13    setTimeout(() => console.log(i), 1000); // 0, 1, 2
14}
  • var는 함수 스코프를 가지므로, 루프가 끝난 후 i 값은 3이 되고, setTimeout에 의해 실행된 모든 함수는 3을 출력합니다.
  • let을 사용하면 setTimeout 콜백 함수 내부의 i는 각 루프마다 새로운 값을 참조하므로 예상대로 0, 1, 2가 출력됩니다.

조기 종료로 가독성 향상하기

루프 처리를 단순화하기 위해 breakcontinue를 적절히 사용하여 가독성을 향상시킵니다.

 1// Example using break
 2for (let i = 0; i < 10; i++) {
 3    if (i === 5) {
 4        break; // Exit the loop
 5    }
 6    console.log(i);
 7}
 8
 9// Example using continue
10for (let i = 0; i < 10; i++) {
11    if (i % 2 === 0) {
12        continue; // Skip to the next iteration
13    }
14    console.log(i);
15}
  • break를 사용하면 반복 처리를 중간에 종료하고 이후의 모든 반복을 건너뛸 수 있습니다.
  • continue를 사용하면 현재 반복 과정을 건너뛰고 다음 반복으로 이동할 수 있습니다.

깊은 중첩 피하기

깊은 중첩은 코드를 읽기 어렵게 만들므로 조기 반환을 사용하거나 기능을 함수로 분리하여 중첩을 얕게 유지하는 것을 목표로 합니다.

 1// Deeply nested example
 2for (let i = 0; i < 5; i++) {
 3    for (let j = 0; j < 5; j++) {
 4        if (i + j > 5) {
 5            console.log(i, j);
 6        }
 7    }
 8}
 9
10// Improved using function decomposition
11function processPairs(i) {
12    for (let j = 0; j < 5; j++) {
13        if (i + j > 5) {
14            console.log(i, j);
15        }
16    }
17}
18
19for (let i = 0; i < 5; i++) {
20    processPairs(i);
21}
  • 이 예제에서는 중첩을 줄이기 위해 함수가 사용되었습니다.

오류 처리를 고려하세요

루프 내에서 오류가 발생할 가능성이 있다면 적절한 오류 처리를 구현하세요.

 1const data = ["123", "abc", "456", "xyz"];
 2
 3// Without Error Handling
 4for (const item of data) {
 5    const result = parseInt(item);
 6    console.log(`Parsed value: ${result}`);
 7}
 8
 9// With Error Handling
10for (const item of data) {
11    try {
12        const result = parseInt(item);
13        if (isNaN(result)) {
14            throw new Error(`Invalid number: ${item}`);
15        }
16        console.log(`Parsed value: ${result}`);
17    } catch (error) {
18        console.error(`Error processing item: ${item}. ${error.message}`);
19    }
20}
  • 이 예제에서는 잘못된 데이터를 처리하기 위해 에러 처리를 수행하며, 문제를 감지하고 보고합니다.

비동기 처리에서 유의할 점

루프에서 비동기 처리를 다룰 때, async/await를 사용하면 간결하고 직관적인 코드를 작성할 수 있습니다.

 1const urls = ["https://example.com/1", "https://example.com/2"];
 2
 3// Proper handling of asynchronous operations
 4async function fetchUrls() {
 5    for (const url of urls) {
 6        const response = await fetch(url);
 7        const data = await response.json();
 8        console.log(data);
 9    }
10}
11
12fetchUrls();
  • 이 코드는 urls 배열에서 URL을 하나씩 비동기로 가져와 JSON 형식으로 결과를 처리합니다. async/await를 사용하면 비동기 작업이 간소화되며, 각 URL에 대한 데이터를 순차적으로 가져와 콘솔에 출력합니다.

비동기 처리에서 for...of 문과 forEach()의 차이를 이해하세요.

 1async function asyncTask(num) {
 2    return new Promise(resolve => {
 3        setTimeout(() => {
 4            console.log(`Task ${num} done`);
 5            resolve();
 6        }, 100);
 7    });
 8}
 9
10async function runWithForOf() {
11    console.log("Start for...of");
12    for (const num of [1, 2, 3]) {
13        await asyncTask(num);
14    }
15    console.log("End for...of");
16}
17
18async function runWithForEach() {
19    console.log("Start forEach");
20    [1, 2, 3].forEach(async num => {
21        await asyncTask(num);
22    });
23    console.log("End forEach");
24}
25
26async function executeExamples() {
27    await runWithForOf();
28    await runWithForEach();
29}
30
31executeExamples();
  • 루프에서 비동기 처리를 다룰 때, async/await와 함께 for...of를 사용하는 경우와 forEach()를 사용하는 경우의 동작 차이를 이 예제에서 보여줍니다.

  • for...of를 사용하면 코드가 순차적으로 실행되며, 루프 내의 await에서 다음 반복으로 진행하기 전에 대기합니다. 반면에, forEach()는 처리를 병렬로 실행합니다.

결론

JavaScript의 for 문은 단순하지만 강력한 도구입니다. 여기에서 소개된 모범 사례를 활용하면 효율적이고 가독성이 높은 코드를 작성할 수 있습니다. 적절한 반복문 구조 선택, 스코프 관리, 오류 처리에 유의하며 유지보수성이 높은 코드를 목표로 하세요.

위의 기사를 보면서 Visual Studio Code를 사용해 우리 유튜브 채널에서 함께 따라할 수 있습니다. 유튜브 채널도 확인해 주세요.

YouTube Video