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의 렉시컬 환경으로 되돌림
- 고차 함수 사용하는 함수형 프로그래밍 기법
- 변수와 반복문 사용 억제하여 오류를 줄이고 가독성 높임
- 배열의 고차 함수 사용 => 배열의 요소로 추가된 함수들은 모두 클로저임
'Books > 모던 JS Deep Dive ✔️' 카테고리의 다른 글
[모던 JS Deep Dive] 26장 - ES6 함수의 추가 기능 (0) | 2022.01.11 |
---|---|
[모던 JS Deep Dive] 25장 - 클래스 (0) | 2022.01.10 |
[모던 JS Deep Dive] 23장 - 실행 컨텍스트 (0) | 2022.01.04 |
[모던 JS Deep Dive] 22장 - this (0) | 2022.01.03 |
[모던 JS Deep Dive] 21장 - 빌트인 객체 (0) | 2021.12.30 |
댓글