[내가 이해하는 자바스크립트] 클로저 (Closure)

1q2w3e4r·2021년 9월 18일
0

클로저란?

내부함수가 외부함수의 맥락에 접근할 수 있는 것을 가르킴.

내부함수

function outter(){
    function inner(){
        var title = 'coding everybody'; 
        alert(title);
    }
    inner();
}
outter(); // coding everybody

외부함수인 outter 함수가 실행되면 내부함수인 inner가 실행되게 되는데 이때 alert(title)이 실행되어 alert창에 coding everybody가 출력되게 된다.

이를 closure 형태로 변경하면 다음과 같다.

function outter(){
    var title = 'coding everybody';  
    function inner(){        
        alert(title);
    }
    inner();
}
outter();

//--------------------------------

function outter(){
    var title = 'coding everybody';  
    return function(){        
        alert(title);
    }
}
inner = outter();
inner();

이렇게 내부함수인 inner는 외부함수의 변수인 title에 접근할 수 있다.

2번째 예제를 보면 outter는 실행 및 반환되어 inner라는 변수에 담긴다.
이때 지역변수인 title은 return에도 없고 반환되었으니 소멸되는 것이 자연스럽지만, inner를 실행하면 전과 똑같은 결과가 나온다.

따라서 closure는
외부함수가 실행되어 반환되어도 내부함수가 외부함수의 변수에 접근할 수 있고,
외부함수는 외부함수의 지역변수를 사용하는 내부함수가 소멸될 때까지 남아있는 것을 의미한다.

다음 예제를 보자

function factory_movie(title){
    return {
        get_title : function (){
            return title;
        },
        set_title : function(_title){
            title = _title
        }
    }
}
ghost = factory_movie('Ghost in the shell');
/*
ghost = { 
	get_title : function() { return 'Ghost in the shell' },
    set_title : function(_title) { 'Ghost in the shell' = _title } 
}
*/
matrix = factory_movie('Matrix');
/*
martix = { 
	get_title : function() { return 'Matrix' },
    set_title : function(_title) { 'Matrix' = _title } 
}
*/
 
alert(ghost.get_title()); // Ghost in the shell
alert(matrix.get_title()); // Matrix
 
ghost.set_title('공각기동대');
/*
ghost = { 
	get_title : function() { return '공각기동대' },
    set_title : function(공각기동대) { 'Ghost in the shell' = 공각기동대 } 
    // Ghost in the shell => 공각기동대
}
*/
alert(ghost.get_title()); // 공각기동대
alert(matrix.get_title()); // Matrix

factory_move는 title을 매개변수로 받아 get_title, set_title을 반환한다.

ghost는 get_title, set_title함수를 가지고 있고 get_title 호출 시 매개변수로 받은 'Ghost in the shell'을 반환한다.
ghost는 get_title, set_title함수를 가지고 있고 get_title 호출 시 매개변수로 받은 'Matrix'을 반환한다.

ghost.set_title을 실행하면 매개변수로 받은 '공각기동대'title이 되어 factory_movie 호출 시 매개변수로 '공각기동대'를 받은 것과 같다.

여기서 알 수 있는 점은 다음과 같다.

  1. 클로저는 객체의 메소드에서도 사용할 수 있다. ghost와 matrix는 get_title, set_title을 메소드로 가지고 있다.
  2. 동일한 외부함수 안에서 만들어진 내부함수나 메소드는 외부함수의 지역변수를 공유한다. 예제의 메소드들은 외부함수인 factory_movie의 파라미터로 전달된 지역변수인 title을 공유하고 있다.
  3. 똑같은 외부함수를 가져도 독립된 객체를 갖는다. ghost와 matrix는 서로에게 영향을 주지 않는다.
  4. private 속성을 이용할 수 있다. title은 정의된 객체인 ghost나 matrix를 통해서만 접근할 수 있으므로 private 하다고 볼 수 있다.

응용

응용예제는 대부분 for문을 예제로 든다.

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

생각은 당연히 0, 1, 2, 3, 4가 찍힐 것 같지만 실상은 5, 5, 5, 5, 5이다.
왜냐면 for문의 i가 var로 선언되어 있기 때문에 호이스팅되어 for문이 아닌 for문 바깥에 선언된 것처럼 바뀌기 때문이다.

우리의 예상대로 결과를 나타내려면 다음과 같이 변경하면 된다.

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]());
}

//or ==========================

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

//or ==========================

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

출처 : 생활코딩 - closure

0개의 댓글

관련 채용 정보