본문 바로가기

Programming/Javascript

12. Javascript 클로저(Closure)(1) - 클로저의 정의 3

 

이제 앞서 살펴본 클로저의 정의와 기본 예제를 바탕으로 조금 더 복잡한(?) 예시를 살펴보도록 하겠습니다. 파라미터 값 등이 추가된 예제이지만, 본질적으로는 앞에서 배우며 살펴본 클로저의 원칙에서 벗어나지 않기 때문에 반복해서 코드를 작성해보시면 금방 익숙해질 수 있는 내용입니다. 

 

function outerFunc(arg1, arg2) {
    var local = 8;
    function innerFunc(innerArg) {
        console.log( (arg1 + arg2) / (innerArg + local) );
    }

    return innerFunc;
}

var exam1 = outerFunc(2, 4);
exam1(2);

 

우선 위 예제를 잘 읽어봅시다. outerFunc( )라는 함수 내부에 내부 함수 innerFunc( )가 존재하고, 이 innerFunc( )를 즉시 실행하지 않고 outerFunc( ) 종료와 함께 외부의 변수로 리턴하는 것은 동일합니다. 다만 여기서 찾아볼 수 있는 차이점은 어떤 것이 있을까요? 

 

바로 outerFunc( ) 함수에 파라미터 값 두 개가 선언되어 있다는 점입니다. 아마 추상적으로나마 함수에서 파라미터 값이 주어진다면 이는 휘발되는 값이라고 생각하는 경우가 있는데, 역시 변수 객체에 저장되는 값 중 하나라는 사실을 잘 상기하고 클로저의 원칙을 정의하면 특별히 다를 것이 없습니다. 

 

우선 위의 예제를 이제까지 해왔던 방식대로 실행 컨텍스트 기준으로 도식화해보도록 하겠습니다. 

 

closure example

 

위에서 설명했다시피, 앞의 아티클에서 살펴보았던 예제와 구조적으로 크게 다르지 않습니다. 다만 여기에서는 outerFunc( )와 innerFunc( )가 실행될 때 각 함수에게 전달되는 파라미터가 존재한다는 점에 주의하여 실행 컨텍스트를 살펴보도록 하겠습니다. 

 

우선 전역 컨텍스트에는 함수 outerFunc와 변수 exam1이 존재하게 됩니다. 그리고 outerFunc( )가 실행되는 지점을 살펴봅시다. '실행'될 때는 outerFunc(2, 4)로 실행되기 때문에 실행 컨텍스트가 생성되면서 변수 객체에 어떤 값들이 존재하는지 살펴보면 됩니다. 우선 변수 local에 8이 선언되어 있고, 함수 innerFunc( )가 존재합니다. 그리고 파라미터 arg1, arg2가 존재하게 되는데 실행 당시 각각 2와 4라는 인자 값이 전달되었습니다. 이렇게 살펴보면 outerFunc 실행 컨텍스트에 존재하는 변수 객체의 구성 요소들이 산출됩니다. 생각보다 간단하죠? 그리고 스코프 체이닝 리스트에는 전역 객체, outerFunc 변수 객체가 존재하게 됩니다. 

 

이제 클로저를 살펴보아야 합니다. 함수 innerFunc( )는 선언만 된 상태로 전역 컨텍스트의 exam1이라는 변수에 리턴됩니다. 그럼 전역 컨텍스트에서 이 innerFunc( )는 어떤 형태로 실행되나요? 바로 exam1(2); 라는 호출 명령을 통해 실행됩니다. 이제 우리가 살펴보았던 클로저의 실행 흐름대로 컨텍스트를 생성하면 됩니다. 

 

innerFunc( )는 전역 컨텍스트에서 클로저로서 실행되며 실행 컨텍스트가 생성됩니다. 다만 여기에는 innerArg라는 파라미터 값이 또 하나 존재한다는 차이점은 있네요. 여기에 들어가는 값은 무엇일까요? 바로 실행할 때 전달된 인자 '2'가 들어갑니다. 그리고 스코프 체이닝은 outerFunc 컨텍스트를 포함해 innerFunc 변수 객체까지 포함됩니다. 

 

이제 innerFunc( ) 함수를 다시 살펴보겠습니다. 

 

function innerFunc(innerArg) {
        console.log( (arg1 + arg2) / (innerArg + local) );
}

 

이 함수에서 정의된 변수들의 값은 클로저의 스코프 체이닝을 통해 아래와 같은 값들을 갖게 됩니다.

innerArg : 2
arg1 : 2
arg2 : 4
local : 8

 

결과적으로 { (2 + 4) / (2 + 8) } 이 실행되므로, 0.6이라는 값이 출력됩니다. 이번 예제에서 클로저의 속성이 크게 달라진 것은 없습니다. 다만, 특정 함수가 실행될 때 전달되는 파라미터 인자 값들도 역시 변수 객체로 전달되어 저장되고, 스코프 체이닝에 따라 그대로 클로저 함수가 이 인자 값들도 참조하게 된다는 점을 기억하면 충분합니다.