본문 바로가기
Books/모던 JS Deep Dive ✔️

[모던 JS Deep Dive] 24장 - 클로저

by Aaron-Kim 2022. 1. 6.

24.0 클로저

  - 클로저함수를 일급 객체로 사용하는 함수형 언어에서 사용되는 중요한 특성

  - MDN => 클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합

  - JS는 렉시컬 스코프를 따르는 프로그래밍 언어

24.1 렉시컬 스코프

  - JS 엔진은 함수를 어디서 호출했는지가 아니라 함수를 어디서 정의했는지에 따라 상위 스코프 결정

    => 렉시컬 스코프 (정적 스코프)

  - 함수를 어디서 호출하는지는 함수의 상위 스코프 결정에 영향 주지 않음

  - 함수의 상위 스코프는 함수를 정의한 위치에 의해 정적으로 결정되고 변하지 않음

  - 실행 컨텍스트의 렉시컬 환경에서 OuterLexicalEnvironmentReference를 통해 상위 렉시컬 환경과 연결됨

    - 스코프 체인

24.2 함수 객체의 내부 슬롯 [[Environment]]

  - 함수는 자신의 내부 슬롯 [[Environment]]에 자신이 정의된 환경, 즉 상위 스코프의 참조를 저장함

    - 함수 정의가 위치하는 스코프가 상위 스코프임

    - 상위 스코프의 참조는 Running Execution Environment의 렉시컬 환경 가리킴

  - 함수 호출 위치와 상위 스코프는 아무런 관련이 없음

  - 함수 렉시컬 환경의 구성 요소인 OuterLexicalEnvironmentReference에는

    함수 객체의 내부 슬롯 [[Environment]]에 저장된 렉시컬 환경의 참조가 할당됨

    - 함수 객체 내부 슬롯 [[Environment]]에 저장된 렉시컬 환경의 참조는 함수의 상위 스코프임

    - 함수 정의 위치에 따라 상위 스코프 결정하는 렉시컬 스코프

24.3 클로저와 렉시컬 환경

  - 외부 함수보다 중첩 함수가 더 오래 유지되는 경우,

    중첩 함수는 이미 생명 주기가 종료한 외부 함수의 변수 참조 가능

     => 이러한 중첩 함수를 클로저라고 함

  - 외부 함수의 실행 컨텍스트가 실행 컨텍스트 스택에서 제거될 때,

    외부 함수의 렉시컬 환경까지 소멸하는 것은 아님

  - JS의 모든 함수는 상위 스코프 기억

  - 상위 스코프의 어떤 식별자도 참조하지 않는 함수는 클로저가 아님

    - 대부분 모던 브라우저는 최적화를 통해 상위 스코프의 어떤 식별자도 참조하지 않으면,

      상위 스코프를 기억하지 않음

    - 중첩 함수가 외부 함수의 변수 참조하더라도 바로 소멸하면 본질적으로 클로저가 아님

    - 외부 함수에서 중첩 함수 통째로 return 해야 클로저가 됨

      - 외부 함수 생명 주기 종료되더라도 나중에 내부 함수에서 외부 함수의 변수 참조 가능

  - 클로저; 중첩 함수가 상위 스코프의 식별자를 참조하고,

              중첩 함수가 외부 함수보다 더 오래 유지되는 경우에 한정하는 것이 일반적임

  - 대부분의 모던 브라우저는 최적화를 통해 상위 스코프의 식별자 중 클로저가 참조하는 식별자만 기억

    - 클로저에 의해 참조되는 상위 스코프의 변수 => free variable (자유 변수)

    - 클로저; 함수가 자유 변수에 대해 닫혀있다 => 자유 변수에 묶여 있는 함수

24.4 클로저의 활용

  - 상태를 안전하게 변경하고 유지하기 위해 사용

  - 상태를 안전하게 은닉 (information hiding)하고 특정 함수에게만 상태 변경 허용하기 위해 사용

  - 전역 변수를 함수의 지역 변수로 바꾸어 의도치 않은 상태 변경 방지

    - 이후 이전 상태 유지하도록 즉시 실행 함수와 클로저 활용

    - 자유 변수는 외부에서 직접 접근 불가능한 은닉된 private 변수가 됨

    - 즉시 실행 함수 내에서 선언된 변수는 인스턴스를 통해 접근 불가,

      즉시 실행 함수 외부에서도 접근할 수 없는 은닉된 변수

  - 외부 상태 변경이나 가변 데이터를 피하고, 불변성을 지향하는 함수형 프로그래밍

    - side-effect 최대한 억제, 오류 피하고 프로그램의 안정성 높이기 위해 클로저 적극적으로 사용

24.5 캡슐화와 정보 은닉

  - 캡슐화: 객체의 상태를 나타내는 프로퍼티와 프로퍼티 참조/조작하는 동작인 메서드를 하나로 묶는 것

    - 정보 은닉; 객체의 특정 프로퍼티/메서드 감추는 목적으로 캡슐화 사용

    - 객체의 상태 변경 방지, 정보 보호, 객체 간 상호 의존성 (결합도, coupling) 낮추기

  - JS에서는 public, private, protected 같은 접근 제한자 제공 X (TS에서는 가능)

    - JS에서 객체의 모든 프로퍼티와 메서드는 기본적으로 public

    - 즉시 실행 함수와 클로저를 이용하면 정보 은닉 가능하게 만들 수 있긴 함

    - 하지만, 단 한 번만 생성되는 클로저로 여러 인스턴스가 하나의 동일한 상위 스코프를 사용해서

      JS는 완전한 정보 은닉 지원 X

    - 최근 표준 사양 제안서에 클래스의 private 필드 정의 가능 ( # 이용 )

24.6 자주 발생하는 실수

  - for 문에 var로 반복 변수 선언하면 함수 레벨 스코프의 특성으로 전역 변수가 됨

    - 즉시 실행 함수와 클로저를 활용해 자유 변수로 만들 수 있음

    - 또는 ES6의 let 키워드 사용하여 반복 변수 선언하면 됨

      - for문 코드 블록이 반복 실행될 때마다 for문 코드 블록의 새로운 렉시컬 환경 생성됨

      - 독립적인 렉시컬 환경이 생성되어 식별자의 값 계속 유지

  - for문이 평가되면 새로운 렉시컬 환경이 생성되고 초기화 변수 식별자, 값 등록

    - 새롭게 생성된 렉시컬 환경을 Running Execution Context의 렉시컬 환경으로 교체

    - for문 코드 블록 반복 실행 모두 종료되면,

      for문 실행되기 이전의 렉시컬 환경을 Running Execution Context의 렉시컬 환경으로 되돌림

   - 고차 함수 사용하는 함수형 프로그래밍 기법

    - 변수와 반복문 사용 억제하여 오류를 줄이고 가독성 높임

    - 배열의 고차 함수 사용 => 배열의 요소로 추가된 함수들은 모두 클로저임

반응형

댓글