[JavaScript] 클로저

Yuhallo·2023년 1월 2일
0

JavaScript

목록 보기
3/9

🧡 클로저

함수와 함수가 선언된 어휘적(lexical)환경의 조합을 말합니다. 이 환경은 클로저가 생산된 시점의 유효범위 내에 있는 모든 지역 변수로 구성됩니다. -MDN

  • 자바스크립트는 어휘적 환경, 즉 렉시컬 스코프(선언의 순서)에 의거해 변수를 조회합니다. 일반적으로 이미 실행이 종료된 함수의 변수나 함수를 참조할 수 있는 링크를 가진 내부함수를 뜻합니다.

  • 자바스크립트의 고유개념이 아니라 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어에서 사용되는 특성입니다.

변수와 호이스팅

  • 클로저를 이해하기 위해서는 변수와 호이스팅에 대해 한번더 짚어봐야 합니다.

  • 변수 선언 키워드 varlet은 거의 같습니다. 차이점은 var은 재선언이 가능하고 let은 불가능하다는 것입니다.

  • var는 선언하기 전에 사용해도 에러가 생기지 않습니다. 변수 선언이 최상위로 호이스팅되고 선언과 초기화가 동시에 진행되기 때문입니다.

  • letconst도 호이스팅(스코프 내부 어디서든 변수 선언은 최상위에 선언된 것 처럼 행동하는 것)은 됩니다. 하지만 TDZ(Temporal Dead Zone) 영역에 호이스팅 되어 사용할 수 없습니다. 이것은 스코프단위로 적용되어 외부스코프에서 선언했더라도 내부 스코프에서 선언하지 않고 쓰인다면 에러가 납니다.

    🎀 TDZ (Temporal Dead Zone)
    let키워드로 선언된 변수는 스코프의 시작에서 변수 선언까지 일시적 사각지대에 빠집니다. 따라서 선언 이전에 참조하면 참조에러('ReferenceError`)가 발생합니다.

    • 코드를 예측하게 하고, 잠재적인 버그를 줄일 수 있습니다.
  • let은 선언단계와 초기화 단계가 나뉩니다. 실제 사용될 코드에서 초기화 단계가 진행됩니다. letvar은 이후에 할당단계를 거칩니다(따라서 letvar은 값을 재할당하고 변경할 수 있습니다). const는 선언과 초기화, 할당이 동시에 진행됩니다. 이러한 과정은 스코프 단위로 이루어집니다.

💚 클로저 함수

쉽게 말하자면 함수 내에서 다른 함수(내부 함수)가 리턴되면, 이 함수를 클로저 함수라 부르고, 외부 함수에 있는 변수에 접근이 가능합니다.

  • 함수를 리턴하는 함수입니다. 리턴하는 함수에 의해 스코프가 구분됩니다. 클로저는 스코프를 이용해 변수의 접근 범위를 닫는(closure: 폐쇄) 핵심을 가집니다. 따라서 변수가 선언된 위치가 중요합니다.

  • 외부함수는 내부함수에 선언된 변수에 접근할 수 없습니다. 바깥 스코프에서는 안 쪽 스코프로의 접근이 불가능하기 때문입니다. 반대로 내부함수는 외부함수에 선언된 변수에 접근할 수 있습니다. 안쪽 스코프는 바깥 스코프에서 선언된 변수에 접근이 가능하기 때문입니다.

  • 내부함수는 외부함수의 지역변수에 접근할 수 있는데, 외부함수의 실행이 끝나 외부함수가 소멸된 이후에도 외부함수의 지역변수를 사용하는 내부함수가 소멸될 때까지 외부 함수 내 변수가 메모리 상에 저장됩니다. 따라서 그 이후에도 내부함수가 외부함수의 변수에 접근할 수 있습니다.(어휘적 환경을 메모리에 저장하므로 가능합니다.)


💚 클로저의 활용

  • 장점 : 클로저는 현재 상태를 기억하고 있다가 상태가 변경되면 최신상태로 유지합니다. 또 변수를 함수내에 숨김으로써 다른이가 접근하여 의도치 않게 값이 변경될 여지를 줄일 수 있습니다.

  • 단점 : 하지만 반대로 함수실행 종료 후 가비지 컬렉션의 대상이 될 객체가 계속해서 메모리 상에 남아있게 되면서 퍼포먼스 저하가 발생할 수 있습니다. 또 클로저를 과용하거나 오용하면 코드가 읽거나 고치기 어려워지고 버그가 발생하기 쉬워지는 부작용도 있습니다.

  • 활용 예시 ) 클로저를 통해 커링(curring, 함수 하나가 n 개의 인자를 받는 대신 n개의 함수를 만들어 각 인자를 받게 하는 방법), 클로저 모듈(변수를 외부 함수 스코프 안 쪽에 감추어 함수 밖에서 노출되는 것을 막는 방법) 등의 패턴을 구현할 수 있습니다.

즉시 실행 함수 표현(IIFE)

  • Immediately Invoked Function Expression입니다. 정의되자마자 즉시 실행되는 함수를 말합니다.var도 블록 레벨 스코프를 가질 수 있게 고려한 것입니다.
  • 모든 코드를 즉시 실행 함수로 감싸서 모든 변수를 즉시 실행 함수의 지역변수로 만드는 것입니다. 이를 활용해 전역 변수의 사용을 제한합니다. 즉 외부에서 접근 불가능한 독립적인 스코프를 가지게 됩니다.
   (function () {
     "함수를 괄호로 둘러싸기";
   }) (); //첫번째 방법

   (function () {
     "전체를 괄호로 둘러싸기";
   } () ); //두번째 방법

   !function () {
     "표현식 앞에 부정연산자 붙이기";
   } (); //세번째 방법

   +function () {
     "표현식 앞에 단항 덧셈 연산자 붙이기";
   } (); //네번째 방법
  • 현재 모던 자바스크립트에서는 let키워드를 사용하면서 이렇게 코드를 작성할 필요가 없어졌습니다.

클로저 모듈 패턴

  • 자바스크립트에서 중요한 패턴 중 하나로, 일반적으로 사용되는 디자인 패턴입니다. 코드 단위를 명확하게 분리하고 구성하기 좋습니다.

  • 클로저를 이용해 내부 함수를 객체에 담아 여러개의 내부 함수를 리턴하도록 만들 수도 있습니다.

  • 클래스를 모방해 관련 있는 변수와 함수를 모아 즉시실행함수로 감싸 하나의 모듈을 만들어 클로저를 기반으로 동작하는 것입니다.

  • 다만 외부스코에서는 내부 스코프의 변수에 접근할 수 없어 함수 내부 변수를 직접 수정할 수는 없습니다. 대신 리턴하는 객체가 제공하는 메서드를 통해 간접적으로 조작할 수 있습니다. 이것을 정보의 접근 제한(캡슐화)라고 합니다.(자바 스크립트는 접근 제한자가 없기 때문에 클로저를 활용해 이런 특징을 흉내내는 것입니다.)

  • 캡슐화를 통해 전역변수로 따로 만들 필요가 없어지면서 side effect를 최소화합니다. 의도되지 않은 변경을 줄이면, 오류로부터 보다 안전하게 값을 보호할 수 있습니다. 즉 클로저로 불필요한 전역 변수 사용을 줄이고 스코프로 값을 안전하게 다루는 것입니다.

  • 함수의 재사용성을 극대화 하여, 함수 하나를 완전히 독립적인 부품 형태로 분리하는 것을 모듈화라고 합니다. 클로저는 데이터와 메서드를 묶어서 모듈화합니다. 하지만 느슨하게 결합한 것으로 언제든 구현을 수정할 수 있는 장점을 가집니다.

    느슨한 결합
    코드 실행 순서에 따라 절차적으로 코드를 작성하는 것이 아니라, 코드가 상징하는 실제 모습과 닮게 코드를 모아 결합하는 것을 의미합니다.


❓ Execution context
❓ lextical environment
❓ 클로저에 대해 좀 더 이해 요망

profile
개발자가 되고 싶어 둥당둥당

0개의 댓글