[심화] 04. Rest/Spread·클로저·타이머
2026. 1. 4. 23:12
JavaScript 심화

Rest/Spread·클로저·타이머: ‘상태’와 ‘시간’을 다루는 감각

문법(… )을 올바르게 구분하고, 클로저와 이벤트 루프 관점에서 타이머를 이해합니다.

Destructuring / Rest / Spread
그림 1. 분해/모으기/펼치기 치트시트
이벤트 루프
그림 2. 타이머와 이벤트 루프(큰 그림)

Rest / Spread: 헷갈리는 이유부터 정리해보기

Rest와 Spread는 둘 다 점 세 개(...)를 사용하지만, 쓰이는 위치가 다릅니다.

  • Rest: “남은 값을 모으는” 문법 (함수 매개변수, 구조 분해 패턴에서 사용)
  • Spread: “값을 펼치는” 문법 (배열/객체 리터럴, 함수 호출에서 사용)
function logAll(first, ...rest) { // Rest
  console.log(first, rest);
}

const arr = [1,2,3];
console.log(...arr); // Spread
주의
Spread로 만든 복사는 얕은 복사입니다. 중첩 객체가 있으면 내부 참조는 그대로 공유됩니다.

Closure: ‘함수 + 외부 상태’가 묶이는 현상

클로저는 “함수가 만들어질 때의 외부 변수 환경을 기억하는 것”으로 이해하시면 가장 편합니다. 실무에서는 캡슐화, 상태 유지, 팩토리 함수 등에서 자연스럽게 등장합니다.

function makeCounter() {
  let n = 0;
  return function () {
    n += 1;
    return n;
  };
}

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
  • 클로저는 강력하지만, 불필요하게 큰 객체를 잡고 있으면 메모리 누수처럼 보일 수 있으니 주의가 필요합니다.
  • 루프에서 콜백을 만들 때는 var 대신 let을 쓰면 의도치 않은 동작을 줄일 수 있습니다.

setTimeout / setInterval: ‘시간’은 정확하지 않을 수 있습니다

타이머는 “정확히 그 시간에 실행”이 아니라, 그 시간 이후에 실행될 수 있도록 큐에 올리는 것에 가깝습니다. 그래서 이벤트 루프와 함께 이해하면 훨씬 자연스럽습니다.

const id = setInterval(() => {
  console.log('tick');
}, 1000);

setTimeout(() => clearInterval(id), 5000);
실무 팁
  • 타이머 정리는 항상 clearTimeout/clearInterval까지 함께 챙겨두시면 안전합니다.
  • Promise의 then/catch는 Microtask로 처리되는 경우가 많아서, 일반 타이머(Task)보다 먼저 실행될 수 있습니다.

참고 링크