본문 바로가기

IT/javascript

[javascript] 클로저(Closure)란?

클로저란?

함수 내부에 선언된 변수는 함수 종료 시, 모두 반환되지만, 외부에서 그 값을 계속 참조할 경우 반환하지 않습니다.
클로저는 이러한 특성을 이용해서 사용되는 데, 함수 내부의 변수를 참조하는 함수를 리턴하는 형식으로 사용됩니다.
    function func() {
        var num = 1;

        return function () {
            return ++num;
        };
    }
    
    var closure = func();
    
    closure(); // 2
    closure(); // 3
    closure(); // 4

func()함수는 num 변수를 선언하고 num 변수를 증가시키는 함수를 반환하는데, func()함수가 종료되어도 num 변수는 사라지지 않고 클로저 함수에서 사용됩니다. 이러한 동작이 가능한 이유는 함수는 1급 객체이고, 실행 컨텍스트라는 특수한 환경을 지니고 있기 때문입니다. 

1급 객체란?

1) 함수를 변수에 저장할 수 있다.
2) 함수를 인자로 전달할 수 있다.
3) 함수를 반환할 수 있다.

실행 컨텍스트란?

2020/12/05 - [IT/javascript] - [javascript] 실행 컨텍스트(Execution Context)

 

클로저를 이용한 캡슐화

    function Person(){
        var name = "";
        
        this.getName = function(){
            return name;
        };
        
        this.setName = function(n){
            name = n;
        };
    }
    
    var person = new Person();
    
    person.setName("kim");
    console.log(person.getName());
생성자 함수 Person은 getName()과 setName() 메소드를 갖는 인스턴스를 생성합니다. 이 메소드들은 자신이 생성되었을 때의 생성자 함수 Person의 스코프에 속한 name 변수를 기억하는 클로저입니다. 생성자 함수 Person의 변수 name은  this에 바인딩된 프로퍼티가 아닌 지역변수입니다. name 변수가 this에 바인딩된 변수라면 외부에서 접근 가능한 변수가 되지만, 지역변수로 선언되었으므로 외부에서 접근할 수 없고, getName(), setName() 메소드를 통해서 접근이 가능합니다. 이러한 클로저의 특징을 이용해 private 변수를 흉내낼 수 있습니다. 

 

자주 발생하는 실수

    
    for (var index = 0; index < 10; index++) {
        setTimeout(function () {
            console.log(index);
        }, 100);
    }
    
0.1초 마다 0에서 9까지 출력할 것으로 예상하겠지만 결과는 그렇지 않습니다. 이유는 setTimeout 내부에 생성된 클로저는 index 값을 받은 시점의 값이 출력되는 것이 아니라 index 변수 자체를 공유하고있기 때문입니다.  

 

let 변수

    for (let index = 0; index < 10; index++) {
        setTimeout(function () {
            console.log(index);
        }, 100);
    }
let은 블록 스코프이기 때문에, 반복문의 각 단계가 같은 index를 공유하지 않습니다.

참조 :
https://victorydntmd.tistory.com/44?category=704012
https://poiemaweb.com/js-closure