모던 자바스크립트 Deep Dive - 24. 클로저

둡둡·2024년 1월 30일

Modern Javascript Deep Dive

목록 보기
25/49

24. 클로저

  • 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어의 중요한 특성
    • cf. 하스켈(Haskell), 리스프(Lisp), 스칼라(Scala) 등
  • (MDN) 함수와 그 함수가 선언된 렉시컬 환경과의 조합
    • 외부 함수 내부에서 중첩 함수를 정의하고 호출하면 외부 함수의 변수에 접근 가능

24.1. 렉시컬 스코프

  • 렉시컬 스코프(정적 스코프): 자바스크립트는 함수를 정의한 위치에 따라 상위 스코프를 결정함
    • 외부 렉시컬 환경에 대한 참조 = 상위 렉시컬 환경 = 상위 스코프
  • 즉, 상위 스코프에 대한 참조는 함수 정의가 평가되는 시점에 정의된 환경(위치)에 의해 결정됨

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

  • 렉시컬 스코프를 위해 내부 슬롯 [[Enviroment]]에 상위 스코프의 참조를 저장함
  • 상위 스코프는 현재 실행 중인 실행 컨텍스트의 렉시컬 환경 참조임

24.3. 클로저와 렉시컬 환경

  • 클로저(closure): 외부 함수보다 중첩 함수가 오래 유지될 때 이미 생명 주기가 종료된 외부 함수의 변수를 참조할 수 있음
      1. 외부 함수 생성할 때 전역 렉시컬 환경을 내부 슬롯에 상위 스코프로 저장함
      1. 중첩 함수가 평가되어 실행될 때 자신의 내부 슬롯에 외부 함수의 렉시컬 환경을 상위 스코프로 저장함
      • (상위 스코프 = 외부 함수 내부 슬롯 = 내부 함수 내부 슬롯)
      1. 외부 함수가 내부 함수를 반환하면서 실행이 종료되면서 생명 주기도 종료됨
      • 외부 함수의 실행 컨텍스트는 제거되지만, 내부 함수에서 참조되고 있기 때문에 렉시컬 환경(내부 슬롯)은 소멸하지 않음 -> 가비지 컬렉션 대상 X
      1. 외부 함수가 반환한 내부 함수를 호출하면 내부 함수의 실행 컨텍스트가 생성되고, 내부 함수 내브 슬롯에 저장된 렉시컬 환경(상위 스코프)을 유지함
  • 상위 스코프의 식별자를 참조하지 않는 함수는 클로저가 아님
  • 일반적으로 클로저는 중첩 함수가 상위 스코프의 식별자를 참조하고, 외부 함수보다 더 오래 유지되는 경우를 말함

24.4. 클로저의 활용

  • 클로저는 상태를 안전하게 은닉 및 유지하고 특정 함수에게만 변경하도록 허용함
const counter = (function() {
  let num = 0;
  
  // 아래 메서드의 상위 스코프는 즉시 실행 함수의 실행 컨텍스트 렉시컬 환경
  // 호출 위치와 관계 없이 즉시 실행 함수의 스코프 식별자를 언제나 참조할 수 있음
  return {
    increase() {
      return ++num;
    },
    decrease() {
      return num > 0 ? --num: 0;
    }   
  };
}());

console.log(counter.increase()); // 1
console.log(counter.increase()); // 2

console.log(counter.decrease()); // 1
console.log(counter.decrease()); // 0
  • 매개변수를 함수로 전달받아 반환하는 고차 함수로도 활용 가능

24.5. 캡슐화와 정보 은닉

  • 캡슐화(encapsulation): 객체의 프로퍼티와 메서드를 하나로 묶는 것
  • 정보 은닉(information hiding): 특정 객체의 프로퍼티나 메서드를 감추기 위해 캡슐화함
    • 정보 은닉을 통해 정보를 보호하고, 객체 간 상호 의존성(결합도)을 낮춤
  • 자바스크립트는 접근 제한자를 제공하지 않음
    • 클로저를 통해 정보 은닉 효과를 만들 수 있음
    • 단, 여러 개의 인스턴스를 생성할 경우, 하나의 동일한 상위 스코프를 공유하기 때문에 일부 변수의 상태가 유지되지 않는 단점이 발생
    • private 필드를 정의할 수 있는 새로운 사양 예상됨

24.6. 자주 발생하는 실수

  • var 키워드 사용: 함수 레벨 스코프이므로 전역 변수가 되어 식별자 값을 유지하기 어려움
    • ES6 let 키워드 사용
      • for문 등 코드 블록을 반복 실행할 때마다 항상 새로운 렉시컬 환경을 생성하고 값을 초기화함
    • 고차 함수 사용
      • 변수와 반복문 사용을 억제하여 오류를 줄이고 가독성 높임
      • ex) Array.forEach, Array.from

[출처] 모던 자바스크립트, Deep Dive

profile
괴발개발라이프

0개의 댓글