자바스크립트 입문_클로저의 의미 및 원리

자바스크립트 2021. 5. 8. 23:14

(본 포스팅은 위키북스의 '코어자바스크립트' 책을 공부하면서 작성되었습니다_내돈내산)

 

" A closure is the combination of a function and the lexical environment within which that function was declared"
                                                                                               -MDN(Mozilla Developer Network)-
  • 클로저는 함수와 그 함수가 선언될 당시의 lexical environment의 상호관계에 따른 현상.
  • '선언될 당시의 lexical environment'는 실행컨텍스트의 구성 요소 중 하나인 outerEnvironmentReference에 해당함.
  • 어떤 컨텍스트를 A, 그 컨텍스트 A에서 선언한 내부함수를 B라고 할때, 내부함수 B가 A의 LexicalEnvironment를 언제나 사용하는 것은 아님. 내부함수에서 외부 변수를 참조하지 않는 경우라면 combination도 발생하지 않음.
  • 내부함수에서 외부 변수를 참조하는 경우에 한해서만 '선언될 당시의 LexicalEnvironment와의 상호관계'가 의미가 있음.
     
    >> 정리해보면 클로저란 "어떤함수에서 선언한 변수를 참조하는 내부함수에서만 발생하는 현상" 으로 볼수있음.

- 외부함수의 변수를 참조하는 내부함수(1) -

var outer = function() {
  var a  = 1;
  var inner = function() {
    console.log(++a);
  };
  inner();
};
outer();
  1. outer함수에서 a를 선언했고, outer의 내부함수인 inner함수에서 a의 값을 1만큼 증가시킨 다음 출력.
  2. inner함수 내부에서는 a를 선언하지 않았기 때문에 environmentRecord에서 값을 찾지 못하므로 outerEnvironmentReference에 지정된 상위 컨텍스트인 outer의 LexicalEnvironment에 접근해서 a를 찾음.
  3. outer 함수의 실행 컨텍스트가 종료되면 LexicalEnvironment에 저장된 식별자(a, inner)에 대한 참조를 지움.
  4. 각 주소에 저장되어 있던 값들은 자신을 참조하는 변수가 하나도 없으므로 가비지컬렉터의 수집대상이 됨.

- 외부함수의 변수를 참조하는 내부함수(2) -

var outer = function() {
  var a  = 1;
  var inner = function() {
    return ++a;
  };
  return inner();
};
var outer2 = outer();
console.log(outer2);
  1. inner 함수 내부에서 외부변수인 a 사용
  2. inner함수가 실행한 결과를 리턴.
  3. outer함수가 종료된 시점에는 a변수를 참조하는 대상이 사라짐.
  4. a, inner 변수의 값들은 언젠가 가비지 컬렉터에 의해 소멸함.
  5. 일반적인 함수 및 내부함수에서의 동작과 차이가 없음.

- 외부 함수의 변수를 참조하는 내부 함수(3) -

var outer = function() {
  var a  = 1;
  var inner = function() {
    return ++a;
  };
  return inner
};
var outer2 = outer();
console.log(outer2());      // 2
console.log(outer2());      // 3
  1. outer의 실행 컨텍스트가 종료된 후에도 inner함수를 호출할 수 있게 만들었음.
  2. outer함수에서 inner함수의 실행결과가 아닌 inner함수 자체를 리턴히켜줌.
  3. outer함수의 실행컨텍스트가 종료된 때 outer2변수는 outer의 실행결과인 inner 함수를 참조하게 됨.
  4. 이후 outer2를 호출하면 앞서 반환된 inner가 실행됨.
  5. inner 함수의 실헝컨텍스트의 environmentRecord에는 수집할 정보가 없고, outerEnvironmentReference에는 inner함수가 선언된 위치의 LexicalEnvironment가 참조 복사됨.
  6. inner 함수는 outer함수 내부에서 선언되었으므로 outer 함수의 LexicalEnvironment를 outerEnvironmentReference로 가짐.
  7. 스코프체이닝에 따라 outer에서 선언한 변수 a에 접근해서 1만큼증가시킨 후 그 값인 2를 반환하고 inner함수의 실행컨텍스트가 종료됨.

  • 가비지 컬렉터는 어떤 값을 참조하는 변수가 하나라도 있으면 그 값은 수집대상에 포함시키지 않기때문에 outer함수가 종료되어도 outer함수의 LexicalEnvironment에 접근이 가능한 것.
  • outer함수는 실행종료시점에 inner함수를 반환하기때문에 외부함수인 outer의 실행이 종료되더라도 내부 함수인 inner함수는 언젠가 outer2를 실행함으로써 호출될 가능성이 생김.

  • 함수의 실행 컨텍스트가 종료된 후에도 LexicalEnvironment가 가비지 컬렉터의 수집 대상에서 제외되는 경우는 지역변수를 참조하는 내부함수가 외부로 전달된 경우가 유일함.

    >> "어떤 함수에서 선언한 변수를 참조하는 내부함수에서만 발생하는 현상"

클로저란 어떤함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상. 반드시 return으로만 발생하는것이 아니며 다른방법으로 내부함수가 외부함수로 전달되는 경우를 모두 나타냄.

 

!! return 없이도 클로저가 발생하는 다양한 경우 !! >> setInterval / setTimeout / eventListener 등

 

 

admin