[JavaScript] 스코프(Scope)와 클로저(Closure)

ttining·2025년 4월 15일

🕹️ 스코프(Scope)란?

"변수에 접근할 수 있는 범위"를 뜻한다.

자바스크립트에서 변수는 정의된 위치에 따라 접근 가능한 범위가 결정된다.
크게 보면 아래 두 가지가 있다.

  • 전역 스코프 (Global Scope)
  • 지역 스코프 (Local Scope) → 함수 스코프 / 블록 스코프
let a = 10; // 전역 스코프

function printA() {
  let b = 20; // 지역 스코프
  console.log(a); // ✅ 가능
  console.log(b); // ✅ 가능
}

printA();
console.log(b); // ❌ ReferenceError

📍 함수 스코프(Function Scope)

자바스크립트에서는 var 키워드로 선언한 변수는 함수 단위로 스코프를 가진다.

function test() {
  var x = 100;
}
console.log(x); // ❌ ReferenceError

📍 블록 스코프(Block Scope)

letconst는 블록({}) 단위로 스코프를 가진다.

{
  let foo = 'bar';
}
console.log(foo); // ❌ ReferenceError
  • 최신 JS에서는 var 대신 항상 let이나 const를 사용하는 게 좋다.

📍 렉시컬 스코프(Lexical Scope)

JS는 렉시컬 스코프를 따르는 언어다.

"렉시컬"이라는 말은 코드가 적힌 위치를 기준으로 스코프가 결정된다는 뜻이다.

function outer() {
  let x = 10;

  function inner() {
    console.log(x);
  }

  inner();
}
outer();

위 코드에서 inner() 함수는 자신이 정의된 위치 기준으로 x를 찾게 된다.
"실행되는 위치"가 아니라, "정의된 위치"를 기준으로 상위 스코프를 찾는 것이 렉시컬 스코프이다.



🕹️ 클로저(Closure)란?

클로저는 "외부 함수의 변수에 접근할 수 있는 내부 함수"이다.

좀 더 정확히 말하면, 외부 함수가 종료된 이후에도 그 함수의 변수에 접근할 수 있는 함수가 클로저이다.

function makeCounter() {
  let count = 0;

  return function () {
    count += 1;
    return count;
  };
}

const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

여기서 내부 함수는 count 변수에 계속 접근하고 있다.
makeCounter()는 이미 실행이 끝난 함수임에도 불구하고 count는 살아있다.

👉 이게 바로 클로저!


✅ 왜 이런 일이 가능할까?

JS에서는 함수가 실행된 이후에도 그 함수가 참조하고 있는 변수들을 메모리에 유지하기 때문에 클로저가 외부 변수에 접근할 수 있는 것!


⚠️ 클로저 주의사항

  • 메모리 누수 가능성

    • 클로저가 불필요하게 너무 많은 변수 참조를 유지하면, GC 대상에서 제외되기 때문에 메모리 점유가 늘어날 수 있다.
  • 의도치 않은 참조 유지

    • 반복문 내부에서 클로저를 만들 때 주의할 것! (예시 참고)
  • 예시

    const functions = [];
    
    for (var i = 0; i < 3; i++) {
      functions.push(() => console.log(i));
    }
    
    functions[0](); // 3
    functions[1](); // 3
    functions[2](); // 3
    • var를 쓰면 i는 공유되기 때문에 예상치 못한 결과가 나온다.
    • 해결하려면 let을 쓰거나, IIFE로 감싸서 클로저를 잘라줘야 한다.
profile
내가 보려고 만든 벨로그 *'-'*

0개의 댓글