JavaScript

for문 내에 변수를 선언해도 괜찮을까?

sangchu 2024. 11. 24. 23:20

도입

JavaScript에서 변수를 선언할 때 종종 마주치는 고민이 있다.

'for문 내부에 변수를 선언해도 될까? 아니면 for문 밖에서 선언하는 것이 더 좋을까?'

 

이런 고민이 생긴 이유는 let과 const는 var과 달리 재선언이 불가능하기 때문이다.

또한 'for문 내부에서 변수를 선언하면 반복이 될 때마다 선언되니 메모리적으로 비효율적이지 않을까? 혹시 문제가 발생하지 않을까?'라는 생각도 들었다(아래 코드의 2번 방식).

 

하지만 실제로 사용해보면 아무런 문제가 발생하지 않는다. 그래서 그냥 넘어갔던 문제인데, 이러한 고민이 들 때마다 찝찝한 마음이 들어서 이번 기회에 확실히 정리하고자 한다.

 

// 1. for 문 밖에서 변수를 미리 선언하고 재할당하는 방식
let ny, nx;
for (let i = 0; i < 4; i++) {
  ny = y + dy[i];
  nx = x + dx[i];
  // ...
}

// 2. for 문 안에서 변수를 선언한 방식
for (let i = 0; i < 4; i++) {
  const ny = y + dy[i];
  const nx = x + dx[i];
  // ...
}

 

결론부터 말하자면, for문 내부에서 변수를 선언해도 괜찮다! 그 이유를 하나씩 살펴보도록 하자.

 

JavaScript의 블록 스코프

for문 내부에서 변수 선언이 가능한 이유는 JavaScript의 블록 스코프 개념을 통해 알 수 있다.

 

JavaScript에서 let과 const로 선언된 변수는 블록 스코프를 가진다. 블록 스코프란 중괄호({})로 둘러싸인 영역 내에서만 변수가 유효한 범위를 의미하며, 변수의 사용 범위를 제한하여 코드의 유지보수를 쉽게 만든다. 간단한 예시를 통해 블록 스코프를 이해해보자.

{
  let x = 10;
  console.log(x); // 10
}
{
  let x = 20;
  console.log(x); // 20
}

위 코드에서 x는 각각 다른 블록에서 선언되었다. 따라서 서로 다른 변수로 취급되어 아무런 문제없이 실행된다.

for문도 마찬가지다. for문이 반복될 때마다 새로운 블록이 생성되고, 그 안에서 선언된 변수는 해당 블록 내에서만 유효하다.

for (let i = 0; i < 3; i++) {
  const number = i * 10;
  console.log(number);
}
// 출력: 0, 10, 20

각 반복마다 number는 새로운 블록 스코프에서 선언되므로, 이전 반복의 number와는 전혀 다른 변수이다.

 

그럼 성능에는 문제가 없을까?

for문이 반복될 때마다 새로운 변수를 선언하면 메모리에 변수가 쌓이니 성능이 안 좋아지지 않을까? 그러니 변수를 계속 새로 만드는 것보다는 재사용하는 게 더 효율적이지 않을까? 라는 생각이 들었다.

하지만 찾아보니 대부분의 경우에는 걱정할 필요가 없다. JavaScript의 최신 엔진들은 대부분 반복적인 변수 생성에 대한 최적화를 잘 수행하기 때문이다. 예를 들어, 반복적으로 생성되는 변수들을 메모리의 특별한 영역에 할당했다가 빠르게 정리하는 방식을 사용한다. 이런 최적화 덕분에 변수를 for문 밖에서 선언하든 안에서 선언하든 실제 성능 차이는 미미하다고 한다.

// 예시 1: 숫자 계산
for (let i = 0; i < 1000; i++) {
  const sum = i + 1;
  console.log(sum);
}

// 예시 2: 문자열 처리
for (let i = 0; i < 1000; i++) {
  const message = `현재 숫자는 ${i}입니다`;
  console.log(message);
}

위와 같이 숫자, 문자열과 같은 간단한 데이터를 다룰 때는 for문 안에서 변수를 선언해도 성능 차이가 거의 없다.

 

변수를 for문 밖에서 선언하는 것이 더 나은 경우

다만 다음과 같은 경우에는 변수를 for문 밖에서 선언하는 것이 더 나은 선택이다.

 

큰 배열이나 객체를 다루는 경우

// 비효율적인 방법
for (let i = 0; i < 1000; i++) {
  const bigArray = new Array(10000).fill(0); // 매번 큰 배열을 새로 생성
  bigArray[i] = i;
}

// 효율적인 방법
const bigArray = new Array(10000).fill(0); // 한 번만 생성
for (let i = 0; i < 1000; i++) {
  bigArray[i] = i;
}

큰 배열을 매번 생성하면 메모리 사용량이 급격히 증가하여 성능에 문제가 생길 수 있다. 따라서 큰 배열은 한 번만 생성하고 재사용하는 것이 좋다.

 

DOM 요소를 다루는 경우

// 비효율적인 방법
for (let i = 0; i < 1000; i++) {
  const element = document.createElement("div"); // 매번 새로운 DOM 요소 생성
  element.textContent = i;
  container.appendChild(element);
}

// 효율적인 방법
const element = document.createElement("div"); // 한 번만 생성
for (let i = 0; i < 1000; i++) {
  element.textContent = i;
  container.appendChild(element.cloneNode(true));
}

DOM 요소를 반복적으로 생성하는 대신, 한 번만 생성한 후 cloneNode를 사용하여 효율적으로 재사용할 수 있다.

 

복잡한 객체나 클래스를 다루는 경우

class ComplexCalculator {
  constructor() {
    // 복잡한 초기화 작업
  }
  calculate(number) {
    return number * 2;
  }
}

// 비효율적인 방법
for (let i = 0; i < 1000; i++) {
  const calculator = new ComplexCalculator(); // 매번 새로운 객체 생성
  const result = calculator.calculate(i);
}

// 효율적인 방법
const calculator = new ComplexCalculator(); // 한 번만 생성
for (let i = 0; i < 1000; i++) {
  const result = calculator.calculate(i);
}

복잡한 객체를 반복적으로 생성하는 것은 불필요한 초기화 비용을 초래한다. 따라서 한 번만 생성하고 재사용하는 것이 좋다.

 

for문 안에 변수를 선언하는게 좋은 경우

반면, 다음과 같은 경우에는 for문 안에 변수를 선언하는 것이 좋다.

 

매 반복마다 새로운 값을 계산해야 하는 경우

for (let i = 0; i < coordinates.length; i++) {
  const nextX = coordinates[i].x + dx[i];
  const nextY = coordinates[i].y + dy[i];
  // nextX, nextY는 매번 새로 계산되어야 하는 값
}

매 반복마다 다른 값을 계산해야 하는 경우에는 각 반복마다 새로운 변수를 선언하는 것이 더 명확하고 가독성이 좋다.

 

변수의 용도가 현재 반복에서만 의미가 있는 경우

for (let i = 0; i < words.length; i++) {
  const reversed = words[i].split("").reverse().join("");
  // reversed는 현재 단어를 뒤집은 결과로, 다음 반복과는 무관
}

변수가 반복 내부에서만 의미가 있을 때는 해당 블록 내에서만 변수를 선언하여 사용 범위를 제한하는 것이 바람직하다.

 

마무리

지금까지 살펴본 내용을 정리해보자.

  1. for문 내부에서 변수를 선언해도 된다.
  2. 이것이 가능한 이유는 블록 스코프 때문이다. 각 반복마다 새로운 블록이 생성되어 변수가 독립적으로 관리된다.
  3. 성능 면에서도 일반적인 경우에는 문제가 되지 않는다.

따라서 for문 내부에서 변수를 선언하는 것은 안전하며, 오히려 변수의 스코프를 명확하게 제한할 수 있어 코드의 가독성과 유지보수성을 높일 수 있다. 단, 대용량 데이터를 다루는 경우에는 상황에 맞게 적절한 판단이 필요하다.

 

참고 자료

    1. MDN - let
    2. MDN - 블록 스코프
    3. JavaScript V8 엔진의 가비지 컬렉션