본문 바로가기

카테고리 없음

클로저(closure)

 

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      function foo() {
        const x = 1;
        const y = 2;

        function bar() {
          debugger;
          console.log(x);
        }
        return bar;
      }

      const bar = foo(); 
      // foo()함수를 변수 bar에 담았다. 
      
      
      bar();
    </script>
  </body>
</html>

 
 
중첩함수 예제코드를 보면  foo()함수 내부에 있는 bar()함수에 Outer environment reference가 담겨져서 리턴된다. foo()함수가 호출스택에 실행되면 내부에 있는 bar()함수에 담겨져 있던  Outer  environment reference이 리턴되어서 x=1을 참조해  콘솔을 실행한다. 정리하면 중첩함수인 bar()함수가 외부에 있는 foo()함수를 상위스코프로 결정한다. 그래서 상위스코프인 foo()함수를 참조해서 x=1이 출력된 것 

 

var outer = function() {
	var a = 1;
    var inner = function() {
    	return ++a;
    };
    return inner;
}
var outer2 = outer();
console.log(outer2());
console.log(outer2());

// outer함수가 실행되면 실행컨텍스트가 쌓이면서 environment Record에 a=1, inner함수가 들어가진다.
// outer함수 실행이 끝나고 inner함수가 반환되면서 outer2변수에 담겨진다. inner함수가 외부에서참조하고 
// 있는 상위스코프는 outer함수이다.
// 이때 a=1은 inner함수의 Outer environment reference에 의해 살아있는 상태 
// outer2함수가 또 실행되면 참조가 살아있는 변수 a=1이 참조카운터에 의해 2가되고 마지막에는 3이된다 
// 전역컨텍스트가 다 종료되기전 변수a=3이 끝까지 살아남는다.

 
클로저는 중첩함수가 상위 스코프의 식별자를  참조하고 있고 중첩함수가 외부 함수보다 더 오래 유지되는 경우에 한정하는 것이 일반적이다.(모던 자바스크립트 Deep Dive 400쪽)  
 
 

var x= 1;

function foo() {
	var x = 10;
    bar();
}

function bar() {
	console.log(x);
} 

// 전역변수 var x=1;
// 렉시컬 환경에는 전역변수 var x=1;, foo()함수객체, bar()함수객체로 구성되어 있다.
// bar()함수객체안에 있는 렉시컬환경에서 상위 스코프인 변수인 x=1을 Outer Lexical Environment(외부 렉시컬
// 환경)으로 참조하고 있다. 
// bar()함수가 foo()함수안에 있다 스코프체인이 발생 


foo();  // 1
bar(); // 1

 
렉시컬 스코프란 함수를 어디서 호출했는지가 아니라 함수를 어디서 정의했는지에 따라 상위스코프를 경정한다. 그리고 함수 객체는 자신이 정의된 스코프, 즉 상위 스코프를 기억하면서 스코프체인이 발생한다. 이때 상위 스코프는 함수 정의가 실행될 때 정적으로 결정된다. 예제 코드를 보면 동적으로 실행할때는 foo()함수 bar()함수의 실행결과가 10이 나오지만 정적으로 실행되서 1이 나온다.  
 
 
 
 
참고자료:  모던자바스크립트 Deep Dive
참고자료:  코어자바스크립트 정재남 인프런 강의