본문 바로가기
개발 공부 일지/코어 자바스크립트 (정재남)

[코어 자바스크립트] 클로저 개념

by yelimu 2025. 3. 4.

클로저

클로저는 자바스크립트 고유의 개념은 아니고, 여러 함수형 프로그래밍 언어에서 보편적으로 나타나는 특성이다. 

- 함수 선언시 만들어지는 유효 범위가 사라진 후에도 그것을 호출할 수 있는 함수
- 생명주기 상 끝난 외부함수의 변수를 참조하는 함수

 

어떤 함수 내부에서 선언된 함수 호출 시 활성화되는 실행 컨텍스트의 L.E (Lexical Environment) 객체는 

┌ environment Record : 식별자 수집 -> 호이스팅 

└ outer Environment Reference  : 스코프 체인

으로 이루어지는데 그 중 outer Environment Reference 가 함수가 선언되는 환경, 즉 외부 함수를 참조한다.

function A(){
	var a = 10;
	function B (){
            var b = 10;
            console.log(++a);
    	}
    B();
    }
A();

함수 A 에서는 변수 b에 접근할 수 없다.

함수 B 에서는 A 내부에서 선언된 변수 a 에 접근할 수 있다. 

왜냐하면 B 내부 environment Record 에서는 a 값을 찾지 못하기때문에 상위 컨텍스트인  outer Environment Reference 에 접근하는데, A의 L.E 를 참조하기 때문이다

 

A 실행 컨텍스트가 종료되면 더이상 a, function B 를 참조하는 대상이 없기 때문에 (참조 카운트 = 0) GC(가비지 컬렉터)의 수거 대상이 된다. 


function A(){
	var a = 10;
	function B (){
            var b = 10;
            return ++a;
    	}
    return B;
    }
var A2 = A();
console.log(A2()); // 2
console.log(A2()); // 3

A 함수 내부에서 B를 실행하거나, B의 실행값 B() 를 리턴하는것이 아니라 B함수 자체를 리턴하면 

A 함수의 실행 컨텍스트가 종료되더라도  A2 변수가 A함수의 실행 결과인 B 함수를 리턴하게 된다. 

→ B함수가 A함수의 LE를 참조하므로 가비지 컬렉터의 수집 대상에서 제외된다. 따라서 a에 접근할 수 있음 

 

a를 참조하는 내부함수 B를 외부로 전달할 때 A 함수의 실행 컨텍스트가 사라져도 변수 a가 사라지지 않는다

- 외부로 전달하는 방법 : return, 또는 콜백함수 (setTimeout, setInterval, addEventListener 등의 인자로 전달되는)

 


메모리 소모는 클로저의 기본 특성이기 때문에

→ 더이상 사용하지 않는다면 참조 카운트를 0으로 만들어야 한다. (메모리 누수 방지)

 

참조하고 있는 식별자에 null 이나 undefined 를 할당한다

var outer = (function() {
    var a = 1;
    var inner = function() {
        return ++a;
    }
    return inner
}

outer2 = outer()
console.log(outer2())
console.log(outer2())
outer2 = null //outer() =inner func에 대한 Reference를 해제시켜서 메모리 누수 방지

 

▼setInterval에 의한 클로저의 메모리 해제

let counter = 0;
const intervalId = setInterval(() => {
  counter++;
  console.log(counter);

  if (counter === 5) {
    clearInterval(intervalId);
    console.log('Interval cleared');
    
    // 클로저가 `counter`를 계속 참조하고 있는 것을 방지하기 위해 `counter`를 null로 설정
    counter = null;
  }
}, 1000);

 

▼ eventListener에 의한 클로저의 메모리 해제

const button = document.querySelector('button');
let clickCount = 0;

// 이벤트 핸들러 함수
function handleClick() {
  clickCount++;
  console.log(`Button clicked ${clickCount} times`);

  if (clickCount === 5) {
    console.log('Removing event handler after 5 clicks');

    // 핸들러를 null로 설정하여 참조 끊기
    button.removeEventListener('click', handleClick);
    handleClick = null;  // 핸들러 자체를 null로 설정하여 더 이상 참조되지 않도록 함
  }
}

// 이벤트 리스너 등록
button.addEventListener('click', handleClick);

이 포스팅은 <코어 자바스크립트> 를 읽고 내용을 정리한 포스팅입니다. 틀린 내용이 있다면 알려주세요 _ _