반응형
Notice
Recent Posts
Recent Comments
Link
250x250
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

동글이의 STORY

클로저 본문

Javascript/자바스크립트 패턴

클로저

dongling 2024. 7. 3. 21:49
728x90
반응형
SMALL

⚡ 클로저의 의미 및 원리

“ 함수와 그 함수가 선언됐을 때의 렉시컬 환경(Lexical environment)과의 조합”

  • 클로저란 어떤 함수에서 선언한 변수를 참조하는 내부함수를 외부로 전달할 경우, 함수의 실행 컨텍스트가 종료된 후에도 해당 변수가 사라지지 않는 현상이다.
  • 함수형 프로그래밍 언어에서 등장하는 보편적인 특성이다. 그런데 다른 언어에서는 일반함수와 클로저함수를 구분해서 사용한다.
  • 근데 JS는 다 클로저 함수라서 개념 구분하려면 어렵게 느껴진다.

🔷 예제로 이해하기

1.1 외부 함수의 변수를 참조하는 내부 함수 (클로저 아님)

var outer = function () {
	var a = 1;
    	var inner = function () {
    	console.log(++a);//2
    };
    inner();
};
outer();
  • inner함수 내부에서는 변수 a를 선언하지 않았기 때문에 상위 컨텍스트인 outer의 LexicalEnvironment에 접근해 변수a를 참조한다.
  • outer함수의 실행컨텍스트가 종료되면, LexicalEnvironment에 저장된 식별자(a, inner)에 대한 참조를 지운다.→ 각 주소에 저장되어 있던 값들은 자신을 참조하는 변수가 하나도 없으므로, 가비지컬렉터(GC)의 수집 대상이 된다.

1.2 외부 함수의 변수를 참조하는 내부 함수 (클로저 아님)

var outer = function () {
	var a = 1;
    	var inner = function () {
    		return ++a;
    };
    return inner ();
};
var outer2 = outer();
console.log(outer2); // 2
  • return inner(); inner함수를 실행한 결과를 리턴한다.
  • 결과적으로 outer함수의 실행컨텍스트가 종료된 시점에는 a변수를 참조하는 대상이 없어진다.→ 결국 inner, a는 가비지 콜렉터에 의해 수집된다.

🤔"예제 1.1 과 1.2는 일반적인 함수 및 내부함수에서의 동작과 차이가 없다.

클로저가 아니다.

그리고 공통적으로 outer함수의 실행 컨텍스트가 종료되기 이전에 inner 함수의 실행 컨텍스트가 종료돼 있으며, 이후 별도로 inner함수를 호출 할 수 없다.

그럼 outer의 실행 컨텍스트가 종료된 후에도 inner 함수를 호출할 수 있게 만들면 어떨까?

1.3 외부 함수의 변수를 참조하는 내부 함수 (클로저 O)

var outer = function () {
	var a = 1;
    	var inner = function () {
    	return ++a;
    };
    return inner; ---->//inner함수 자체를 return!!
};
var outer2 = outer();

console.log(outer2());
// 2 출력

console.log(outer2());
// 3 출력

  • return inner를 통해 함수 자체를 반환했다. outer의 실행 컨텍스트가 종료될 때,
  • outer2의 변수는 outer의 실행결과인 inner함수를 참조하게 된다.
  • 즉, outer2를 호출하면 inner함수가 실행된다.
  • inner함수는 outer함수 내부에서 선언되었으므로, outer함수의 LexicalEnvironment가 담긴다.
  • 스코프 체이닝에 따라 outer에서 선언한 변수a에 접근하여 1만큼 증가 시킨 2를 반환하며 inner의 실행컨텍스트가 종료된다.
  • outer2를 호출하면 같은 방식으로 a의 값이 1 증가되어 3이 출력된다.
  • 가비지컬렉터는 어떤 값을 참조하는 변수가 하나라도 있다면 그 값은 수집 대상에 포함시키지 않기 때문에 outer함수가 종료되어도 outer함수는 inner함수의 변수 참조 때문에 GC의 대상이 되지 않는다.

💡 클로저란 어떤 함수에서 선언한 변수를 참조하는 내부함수에서 발생하는 현상이다.

클로저란 어떤 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우, A의 실행컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상

🤪주의사항!

외부로 전달이 return만을 의미하지는 않는다.

1.4 return 없이도 클로저가 발생하는 다양한 경우

//(1) setInterval/setTimeout
(function(){
  var a =0;
  var intervalId = null;
  var inner = function(){
    	if (++a >= 10){
          clearInterval(intervalId);
        }
    console.log(a);
  };
  intervalId = setInterval(inner, 1000);
})();

  • 별도의 외부객체인 window의 메서드(setInterval/setTimeout)에 전달할 콜백 함수 내부에서 지역변수를 참조한다.
//(2) eventListener
(function(){
  var count =0;
  var button = document.creatElement('button');
  button.innerText = 'click';
  button.addEventListener('click', function(){
    	console.log(++count, 'times clicked');
  	});
  	document.body.appendChild(button);
})();

  • 별도의 외부객체인 DOM의 메서드(addEventListener)에 등록할 handler함수 내부에서 지역변수를 참조한다.두 상황 모두 지역변수를 참조하는 내부함수를 외부에 전달했기 때문에 클로저 입니다.

🔶 클로저와 메모리 관리

메모리 소모는 클로저의 본질적인 특성 중 하나이다. 이러한 특성을 정확히 이해하고 잘 활용하도록 하자.

**'메모리 누수'**라는 표현은 개발자의 의도와는 달리 어떤값의 참조 카운트가 0이 되지 않아 GC의 수거대상이 않는 경우에는 맞는 표현이다.

하지만, 이런 메모리 누수는 최근 JS엔진에서는 거의 발생하지 않는다.

메모리를 어떻게 관리할까?

→ 지역변수의 필요성이 사라졌다면 참조 카운트를 0으로 만들어주면 된다.

그렇다면, 참조 카운트를 0으로 만들어주는 방법은?

식별자에 참조형이 아닌 기본형 데이터(보통 null이나 undefiend)를 할당하면 된다.

728x90
반응형
LIST

'Javascript > 자바스크립트 패턴' 카테고리의 다른 글

싱글톤 패턴  (0) 2024.07.03
메모이제이션 패턴  (1) 2024.07.03
고차함수 / 커링 / 부분적용함수  (0) 2024.07.03
프라미스 패턴  (0) 2024.07.03
콜백 패턴  (0) 2024.07.03