드디어 정확히 알게된 클로저와 클로저 원리

신은수·2023년 5월 13일
0

VanillaJS

목록 보기
9/11
post-thumbnail

1. 클로저의 의미 및 원리 이해

1) 클로저란?

클로저는 함수와 그 함수가 선언될 당시의 lexical environment의 상호관계에 따른 현상

2) 예제를 통해 알아보는 클로저

a) Lexical environment, EnvironmentReference, OuterEnvironmentReference

  • EnvironmentReference(ER): 식별자에 대한 정보
  • OuterEnvironmentReference(외부정보): 현재 호출된 함수가 선언될 당시의 LexcialEnvironment를 참조
  var outer = function(){
      var a = 1;
      var inner = function(){
          console.log(++a);
      }
      inner();
  }
  outer(); // outer 함수가 종료되면 식별자들(a,inner)에 대한 참조 지움
		   // 각 주소에 저장되어 있던 값들은 
		   // 자신을 참조하는 변수가 없으므로 가비지 컬렉터의 대상이 됨
		

b) 클로저

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

var outer2 = outer(); 
console.log(outer2()); // 2
console.log(outer2()); // 3

q) outer함수의 실행이 종료되면 outer함수의 식별자인 a의 값도 가비지 컬렉터의 대상이 되어서, outer2()를 실행했을 때 undefined 가 나와야하는 것 아닌가?
a) 가비지 컬렉터는 어떤 값을 참조하는 변수가 하나라도 있다면 그 값은 수집 대상에 포함하지 않는다.

외부 함수인 outer의 실행이 종료되더라도 내부 함수인 inner 함수는 언젠가 outer2를 실행함으로써 호출될 가능성이 열림, 언젠가 inner함수의 실행 컨텍스트가 활성화되면 outerEnvironmentReference가 outer함수의 LexicalEnvironment를 필요할 것이므로 수집대상에서 제외됨.

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

c) return이 없어도 클로저가 발생하는 경우

(function (){
  	var a = 0;
  	var interValid = null;
  	var inner = function(){
     	if(++a>=10){
        	clearInterval(intervalid);  
        }
      	console.log(a);
    };
  	intervalid = setInterval(inner, 1000);
})();

지역변수를 참조하는 내부함수를 외부에 전달했기 때문에 클로저


2. 클로저와 메모리 관리

1) 메모리 누수

개발자의 의도와 달리 어떤 값의 참조 카운트가 0이 되지 않아 가비지 컬렉터의 수거대상이 되지 않는 경우

let x = {
 	y: {
     	z: 1 
    }
}

// x가 참조하는 객체를 obj1라하자 
let a = x; // obj1의 참조카운트: 2 (x와 a)
x = 1; // obj1의 참조카운트: 1 (a)

// y가 참조하는 객체를 obj2라고 하자
let b = a.y; // obj2의 참조카운트: 2 (a.y와 b)
a = 2; // obj2의 참조카운트: 1 (b)

b가 object2를 참조하기 때문에 object1 객체는 제거되지 않음
object1 객체는 사용하진 않지만 불필요하게 남아있게 됨
이러한 상황을 메모리 누수라고 함

+다양한 메모리 누수상황

2) 클로저의 메모리관리

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

var outer2 = outer(); 
console.log(outer2()); // 2
console.log(outer2()); // 3
outer2 = null // outer2 식별자의 inner 함수 참조를 끊음
profile
🙌꿈꾸는 프론트엔드 개발자 신은수입니당🙌

0개의 댓글