원글 : https://programmer-seva.tistory.com/37?category=615259

1
2
3
4
5
6
7
8
function outerFunc(){
    var x = 10;
    var innerFunc = function() { console.log(x); }
    return innerFunc;
}
 
var inner = outerFunc();
inner();
cs


위 예제를 그림으로 표현하면 아래와 같다.

 

예제와 그림을 보면 알 수 있듯이 outerFunc 실행 컨텍스트는 사라졌지만, outerFunc 변수 객체는 여전히 남아있고, innerFunc의 스코프 체인으로 참조되고 있다.

이것이 바로 자바스크립트에서 구현한 "클로저"라는 개념이다.


자바스크립트 함수는 일급 객체로 취급된다.

이는 함수를 다른 함수의 인자로 넘길 수도 있고, return으로 함수를 통째로 반환받을 수도 있다.

앞의 예제에서 중요하게 볼 점은 최종 반환되는 함수가 외부 함수의 지역변수에 접근하고 있다는 것이 중요하다.


이 지역변수에 접근하려면, 함수가 종료되어 외부 함수의 컨텍스트가 반환되더라도 변수 객체는 반환되는 내부 함수의 스코프 체인에 그대로 남아있어먄 접근할 수 있다. 이것이 바로 클로저이다.


쉽게 풀어 말하면, "이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 함수를 클로저라고 한다"

따라서 위의 예제에서는 outerFunc에서 선언된 x를 참조하는 innerFunc가 클로저가 된다.

클로저로 참조되는 외부 변수, 앞 예제에서는 outerFunc의 x와 같은 변수를 "자유 변수(Free variable)"라고 한다.

클로저는 "자유 변수에 엮여있는 함수"로 많이들 표현한다.


1
2
3
4
5
6
7
8
9
10
11
function outerFunc(arg1, arg2){
    var local = 8;
    function innerFunc(innerArg){
        console.log((arg1 + arg2)/(innerArg + local));
    }
    
    return innerFunc;
}
 
var exam1 = outerFunc(24);
exam1(2);
cs

위 예제에서는 outerFunc() 함수를 호출하고 반환되는 함수 객체인 innerFunc()가 exam1으로 참조된다.

이것은 exam1(n)의 형태로 실행될 수 있다.


여기서 outerFunc()가 실행되면서 생성되는 변수 객체가 스코프 체인에 들어가게 되고, 이 스코프 체인은 innerFunc의 스코프 체인으로 참조된다.


즉, outerFunc() 함수가 종료되었지만, 여전히 내부 함수(innerFunc())의 [[scope]]으로 참조되므로 가비지 컬렉션의 대상이 되지 않고 여전히 접근이 가능하게 살아있다.


innerFunc()에서 참조하고자 하는 변수 local에 접근이 가능하도록 클로저가 만들어 진다.

outerFunc 변수 객체의 프로퍼티 값은 여전히 읽기 및 쓰기까지 가능하다.


위 코드 동작을 그림으로 나타내면 아래와 같다.

 


※ 클로저에서 접근하는 변수는 대부분이 스코프 체인 첫 번째 객체가 아닌 그 이후 객체에 존재한다.

   이는 성능적인 면과 자원적인 면에서 문제를 유발시킬 수 있는 여지가 있다.

   이러한 성능 이슈를 잘 해결하여 클로저를 사용해야 한다. 

   너무 많은 식별자를 인식하지 않도록 설계해서 사용하도록 한다.

Posted by 프로그래머세바 박현진

+ Recent posts