ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 클로저에 대해서
    개발 2020. 4. 1. 18:59

    클로저란?

    렉시컬 스코프에 의존해 코드를 작성한 결과로 발생합니다. 모든 코드에서 클로저는 생성되고 사용됩니다. 

    즉, 클로저는 함수가 속한 렉시컬 스코프를 기억하여 함수가 렉시컬 스코프 밖에서 실행될 때에도 이 스코프에 접근할 수 있게 하는 기능을 뜻합니다. 앞서 블로깅한 스코프에 대해서 컨텐츠를 충분히 잘 이해했다면 클로저에 대한 개념은 좀 더 쉽고 자연스럽게 받아드려질 것입니다. 클로저는 자바스크립트의 모든 곳에 존재하고 새롭게 문법과 패턴을 배워야 할 특별한 것이 아닌 그저 인식하고 받아들이면 됩니다.


    다음 예시코드를 보면서 좀 더 자세하게 클로저에 대하여 알아보도록 하겠습니다.

    function outer(){
      let a = 5;
      function inner(){
        console.log(a);  // 5
      }
      return inner;
    }
    let global = outer();
    global();  // 5

    위의 코드는 중첩 스코프를 다룰 때 작성했던 예시코드와 비슷합니다. 함수 inner()는 렉시컬 스코프의 규칙처럼 outer함수 내부에서 선언되었으므로 상위 스코프는 outer함수이고 중첩 스코프이기 때문에 inner함수 내부에서 변수 a를 참조할 수 있습니다.

    이 outer()함수는 inner()함수를 참조하는 함수 객체 자체를 반환합니다. outer를 실행하여 반환한 inner()함수를 변수 global에 대입하고 global()을 호출했습니다. 즉, global()은 outer()함수의 내부함수인 inner()를 호출한 것입니다. inner함수는 outer함수의 내부함수이지만 이 처럼 렉시컬 스코프 밖에서 실행이 됩니다.

     

    자바스크립트는 객체가 생성되었을 때 자동으로 메모리를 할당하고 더는 사용하지 않는 메모리는 해제시키는데 이 것을 '가비지컬렉션' 이라고 합니다. 이 사실을 보면 엔진이 가비지컬렉션을 사용하여 outer()가 실행된 후에는 더이상 사용하지 않는 메모리라 생각하고 outer()의 내부 스코프가 사라졌다고 보는게 자연스럽겠지만 클로저가 있기 때문에 outer()의 내부 스코프는 inner()함수에서 아직 '사용 중' 이므로 해제되지 않습니다. inner함수가 선언 된 위치에 의해서 inner()함수는 outer()함수 스코프에 대한 렉시컬 스코프 클로저를 가지고, outer()함수는 inner()함수가 나중에 참조할 수 있도록 스코프를 살려두는 것 입니다.

     

    즉, inner()함수는 여전히 outer()함수 스코프에 대한 참조를 가지는데, 그 참조를 바로 클로저라고 부릅니다.


    클로저를 사용하여 API의 속성 메서드 만들기

    다음 예시코드는 클로저를 사용하여 함수안에 비공개 데이터 변수를 넣어 private한 모듈을 만든 예제코드 입니다.

    function getPrivate(){
      let arr = [1, 2, 3];
      let str = "hello";
      
      function something(){
        console.log(arr.join(""));
      }
      function another(){
        console.log(str + " word!");
      }
      
      return {
        something: something,
        another: another
      };
    }
    
    let foo = getPrivate();
    
    foo.something();  // 123
    foo.another();  // hello word!

    먼저 이 코드에서 모듈 패턴을 사용하려면 두 가지 조건이 있습니다.

    1. getPrivate()은 그저 하나의 함수일 뿐이지만, 모듈 인스턴스를 생성하려면 이 함수가 최소 한번은 호출되어야 합니다. 최외곽 함수가( 이 코드에서는 getPrivate()함수를 뜻합니다. ) 실행되지 않으면 내부 스코프와 클로저는 생성되지 않습니다.
    2. getPrivate() 함수는 객체를 반환합니다. 반환되는 객체는 객체-리터럴 문법 { key: value} 에 따라 표기됩니다. 해당 객체는 내장 함수들에 대한 참조를 가지지만 내장 변수 ( 변수 arr과 str )에 대한 참조는 가지지 않습니다. 내장 변수는 비공개로 숨겨져 있습니다. 이객체의 반환 값은 본질적으로 모듈의 공개 API라고 생각할 수 있습니다. 

    객체의 반환 값은 최종적으로 외부 변수인 foo에 대입되고, foo.something()과 같은 방식으로 API의 속성 메서드에 접근할 수 있습니다.

     

    위 코드에 예시를 들지않고 모듈패턴의 두가지 조건을 다시한번 정리하자면 다음과 같습니다.

    • 최외곽 래퍼 함수를 호출하여 외곽 스코프를 생성한다.
    • 래핑 함수의 반환 값은 반드시 하나 이상의 내부 함수 참조를 가져야 하고, 그 내부 함수는 래퍼의 비공개 내부 스코프에 대한 클로저를 가져야 합니다.

     

    '개발' 카테고리의 다른 글

    prototype과 prototype Chain  (0) 2020.04.14
    생성자와 new  (0) 2020.04.12
    객체지향 프로그래밍  (0) 2020.04.12
    재귀함수  (0) 2020.04.12
    스코프에 대해서  (2) 2020.03.31
Designed by Tistory.