Programming/JavaScript

클로저(closure)

잇나우 2019. 12. 15. 18:47
반응형

접근하려고 하는 외부함수의 생명주기가 종료됬지만, 내부함수가 참조 하고 있어서 외부함수에 접근할 수 있는갓

 

내부함수

자바스크립트는 함수 안에서 또 다른 함수를 선언할 수 있습니다.

function outter(){
    function inner(){
        var title = 'Hello world'; 
        alert(title);
    }
    inner();
}
outter();

함수 outter의 내부에는 함수 inner가 정의되어 있다. 함수 inner를 내부함수라고 한다.

내부함수는 외부함수의 지역변수에 접근할 수 있다.

function outter(){
    var title = 'Hello world';  
    function inner(){        
        alert(title);
    }
    inner();
}
outter(); // Hello world

내부함수 inner에서 title을 호출했을때 외부함수의 지역변수인 title을 접근하여 Hello world를 출력하였다.

클로저

내부함수는 외부함수와 지역변수, 전역변수에 접근 할 수 있는데 외부함수의 실행이 끝나서 외부함수가 소멸된 이후에도 내부함수가 외부함수의 변수에 접근 할 수 있다. 이러한 한것을 클로저라고 한다.

function outter(){
    var title = 'Hello world';  
    return function(){        
        alert(title);
    }
}
inner = outter();
inner();

outter 함수안에 지역변수 title과 내부함수가 존재하는 상황에서 outter를 호출하였고 그 결과가 변수 inner에 담긴다. 그 결과는 이름이 없는 함수다. 마지막 행으로 넘어가면 이미 outter 함수의 실행이 끝났기 때문에 이 함수의 지역변수는 소멸되어야 하는것이 자연스럽다. 하지만 함수 inner를 실행했을때 Hellow world가 출력된 것은 외부함수의 지역변수인 title이 소멸되지 않았다는 것을 의미한다. 클로저란 내부함수가 외부함수의 지역변수에 접근 할 수 있고, 외부함수는 지역변수를 사용하는 내부함수가 소멸될 때까지 소멸되지 않는 특성을 의미한다.

function factory_movie(title){
    return {
        get_title : function (){
            return title;
        },
        set_title : function(_title){
            title = _title
        }
    }
}
ghost = factory_movie('Ghost in the shell');
matrix = factory_movie('Matrix');
 
alert(ghost.get_title());    // Ghost in the shell 출력
alert(matrix.get_title());	 // Matrix 출력
 
ghost.set_title('공각기동대');   // _title의 값이 바뀌면서 결국 title의 값이 바뀌게된다.
 
alert(ghost.get_title());    // 공각기동대 출력
alert(matrix.get_title());	 // Matrix 출력

factory_movie 함수는 리턴값으로 객체를 리턴하고 있다. 객체는 2개의 프로퍼티가 있고 그 객체의 첫번째 프로퍼티인 get_title의 값은 함수 이기 때문에 get_title은 메소드이다. (set_title도 마찬가지) 2개의 메소드는 factory_movie라는 함수의 내부함수이며 객체의 소속이다. get_title의 메소드를 호출하면 title이란값을 리턴하는데 이 title은 외부함수인 factory_movie의 매개변수인 title이며 이 title은 지역변수라 할 수 있다. set_title이란 메소드는 첫번째 매개변수로 _title이란 값을 갖게 되는데 이 값은 결국 외부함수의 매개변수인 title을 가리키게 된다. 

factory_movie함수의 Ghost in the shell 인자를 넣고 실행하게 되면 리턴값 (2개의 메소드를 담고있는 객체)를 ghost에 담는다. matrix에도 마찬가지로 담는다. 이때 ghost와 matrix에 담겨있는 컨텍스트는 서로 다르다. ghost의 경우 title의 값이 Ghost in the shell이었고 matrix의 경우 title의 값이 matrix이다. ghost와 matrix는 똑같이 객체를 담고 있지만 내부적으로 메소드들이 가지고있는 title의 값은 다르다. 각각 Ghost in the shell와 Matrix를 출력하게 된다.

ghost.set_title('공각기동대');로 ghost의 set_title의 _title의 값을 변경하게 되면 결국 지역변수인 title의 함수의 값또한 변하게 되어 다시 gosht와 matrix의 값을 출력하게 되면 공각기동대와 Matrix로 출력이 되게된다.

외부함수가 실행될 때마다 새로운 지역변수를 포함하는 클로저가 생성되기 때문에 ghost와 matrix는 서로 완전히 독립된 객체가 된다.  factory_movie의 지역변수 title은 2행에서 정의된 객체의 메소드에서만 접근 할 수 있는 값이다. 이 말은 title의 값을 읽고 수정 할 수 있는 것은 factory_movie 메소드를 통해서 만들어진 객체 뿐이라는 의미다. JavaScript는 기본적으로 Private한 속성을 지원하지 않는데, 클로저의 이러한 특성을 이용해서 Private한 속성을 사용할 수 있게된다.

프라이빗 변수

Private 속성은 객체의 외부에서는 접근 할 수 없는 외부에 감춰진 속성이나 메소드를 의미한다. 이를 통해서 객체의 내부에서만 사용해야 하는 값이 노출됨으로서 생길 수 있는 오류를 줄일 수 있다. 자바와 같은 언어에서는 이러한 특성을 언어 문법 차원에서 지원하고 있다.

var arr = []
for(var i = 0; i < 5; i++){
    arr[i] = function(){
        return i;
    }
}
for(var index in arr) {
    console.log(arr[index]());
}

위 코드를 실행하면 01234가 아닌 55555가 출력된다. 그 이유는 for문의 i의 값은 함수 function(){ return i; }의 i의 값이 아니기 때문이다.

var arr = []
for(var i = 0; i < 5; i++){
    arr[i] = function(id) {
        return function(){
            return id;
        }
    }(i);
}
for(var index in arr) {
    console.log(arr[index]());
}

for문이 돌때마다 함수가 실행되는데 함수가 실행되면서 id매개변수의 값으로 i의 값을 받아서 함수 내부로 전달하고 있다. 전달과 동시에 내부함수를 리턴하고 있는데 그 내부함수는 내부적으로 외부함수의 지역변수를 id를 리턴하고 있는 상황이다.

반응형

'Programming > JavaScript' 카테고리의 다른 글

함수의 호출 apply  (0) 2019.12.16
arguments  (0) 2019.12.16
유효범위(Scope)  (0) 2019.12.14
객체  (0) 2019.12.14
배열  (0) 2019.12.11