Scope와 Closure(feat. 정보 은닉)

세하·2025년 8월 25일

JavaScript

목록 보기
3/10

Scope

스코프(Scope)는 변수와 함수에 접근할 수 있는 유효 범위를 의미
코드가 실행될 때, 자바스크립트 엔진은 이 스코프를 기준으로 특정 변수에 접근할 수 있는지 없는지를 결정한다.

JS에서 스코프는 기본적으로 함수가 선언될 때(Lexical Scoping) 결정되지만, 실제 스코프가 활성화되고 변수가 채워지는 것은 함수가 호출될 때이다.

  1. 전역 스코프: 코드 전체에서 접근 가능한 가장 바깥쪽 스코프
  2. 함수 스코프: 함수가 호출될 때 생성되며, 함수 내부에서만 접근할 수 있다. 이 안에는 매개변수와 함수 내에서 선언된 변수들이 포함됨
// 전역 스코프
const globalVar = '전역 변수';

function outerFunc() {
  // 외부 함수 스코프
  const outerVar = '외부 함수 변수';

  function innerFunc() {
    // 내부 함수 스코프
    const innerVar = '내부 함수 변수';
    console.log(globalVar);    // 접근 가능
    console.log(outerVar);     // 접근 가능
    console.log(innerVar);     // 접근 가능
  }

  innerFunc();
}

outerFunc();

outerFunc가 호출될 때 outerFunc의 스코프가 생성되고, 그 안에서 innerFunc가 호출될 때 innerFunc의 스코프가 생성된다. (중첩된 구조)

Scope Chain

스코프 체인(Scope Chain)은 자바스크립트 엔진이 변수를 찾기 위해 현재 스코프에서부터 상위 스코프로 차례대로 거슬러 올라가는 과정

변수를 사용하면, 엔진은 다음과 같은 순서로 변수를 찾는다.

  1. (현재 스코프): 현재 실행 중인 스코프에서 변수가 있는지 먼저 찾아봄
  2. (상위 스코프): 없으면, 바로 바깥쪽(상위) 스코프로 이동하여 변수를 찾음
  3. (전역 스코프): 이 과정을 계속 반복하다가 전역 스코프까지 도달
  4. 전역 스코프에서도 변수를 찾지 못하면 ReferenceError가 발생한다

innerFunc 내부에서 console.log(outerVar)를 실행할 때의 과정

  1. innerFunc 스코프에서 outerVar를 찾는다. -> 없음
  2. 바로 바깥인 outerFunc 스코프로 이동하여 outerVar를 찾는다. -> 찾음! 값: '외부 함수 변수'
  3. 찾았으므로 검색을 중단하고 해당 값을 사용한다.

Closure : 사라져야 할 스코프를 기억하는 함수

클로저(Closure)는 함수가 선언될 때의 렉시컬 환경(Lexical Environment)을 기억하여, 함수가 자신의 스코프 밖에서 호출될 때에도 그 환경에 접근할 수 있게 해주는 현상이다.
즉, 함수는 자신이 선언된 스코프를 절대 잊지 않는다.

클로저의 조건

  1. 함수 안에 내부 함수가 있어야 한다
  2. 내부 함수가 외부 함수의 변수를 참조해야 한다
  3. 내부 함수가 외부 함수 밖에서 호출되어야 한다 (보통 return을 통해 호출)
function createCounter() {
  let count = 0; // 외부 함수의 변수 (자유 변수)

  // 이 내부 함수가 바로 클로저
  return function() { 
    count++;
    console.log(count);
  };
}

// counter 함수는 createCounter의 실행 컨텍스트(스코프)를 기억한다.
const counter = createCounter(); 

// createCounter 함수는 이미 실행이 끝나 사라졌지만,
// counter 함수는 자신이 태어난 환경의 변수 'count'에 여전히 접근 가능함
counter(); // 1
counter(); // 2
counter(); // 3

동작 원리

  1. createCounter()가 호출되면, count 변수가 담긴 스코프가 생성됨
  2. createCounter()는 내부 함수를 반환하고 실행이 종료된다. 이때 count 변수가 있는 스코프는 원래대로라면 사라져야 함.
  3. 하지만 반환된 내부 함수(이제 counter 변수에 할당됨)가 count 변수를 참조하고 있기 때문에, 자바스크립트 가비지 컬렉터는 count가 있는 스코프를 없애지 않고 메모리에 남겨둔다.
  4. 그 결과, counter()를 호출할 때마다 죽지 않고 살아있는 count 변수에 계속 접근하여 값을 증가시킬 수 있음

이처럼 클로저는 데이터를 특정 함수와 묶어 외부로부터의 접근을 제한하고, 상태를 안전하게 유지하고자 할 때 매우 유용하게 사용된다.
이를 정보 은닉(Information Hiding) 이라고 함

0개의 댓글