클로저는 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어 (예: 하스켈, 리스프, 얼랭, 스칼라등)에서 사용되는 중요한 특성이다. 클로저는 자바스크립트 고유의 개념이 아니므로 글로저의 정의가 ECMAScript 사양에 등장하지 않는다.
MDN 에서는 클로저를 다음과 같이 정의한다.
A closure is the combination of a function and the lexical enviroment within which that function was delared.
클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다.
const x = 1;
function outerFunc() {
const x = 10;
function innerFunc() {
console.log(x); // 10
}
innerFunc();
}
outerFunc();
위 예제에서 중첩함수 innerFunc의 상위 스코프는 외부함수 outerFunc의 스코프이다. 따라서 중첩함수 innerFunc 내부에서 자신을 포함하고 있는 외부 함수 outerFunc의 x 변수에 접근할 수 있다.
만약 innerFunc 가 outerFunc 함수의 내부에서 정의된 중첩함수가 아니라면 innerFunc 함수를 outerFunc 함수의 내부에서 호출한다 하더라도 outerFunc함수의 변수에 접근할 수 없다. (아래 예시)
const x = 1;
function outerFunc() {
const x = 10;
innerFunc();
}
function innerFunc() {
console.log(x); // 1
}
outerFunc();
✅ 렉시컬 스코프는 뭘까? 자바스크립트 엔진은 함수를 어디서 호출했는지가 아니라 함수를 어디에 정의했는지에 따라 상위 스코프를 결정한다. 이를 렉시컬 스코프(정적 스코프)라 한다.
✅ 함수의 상위 스코프는 함수를 어디서 정의했느냐에 따라 결정된다.
✅ 스코프의 실체는 실행 컨텍스트의 렉시컬 환경이다. 이 렉시컬 환경은 자신의 외부 렉시컬 환경에 대한 참조를 통해 상위 렉시컬 환경과 연결된다. -> scope chain
✅ 렉시컬 환경의 "외부 렉시컬 환경에 대한 참조"에 저장할 참조값, 즉 상위 스코프에 대한 참조는 함수 정의가 평가되는 시점에 함수가 정의된 환경(위치)에 의해 결정된다. 이것이 바로 렉시컬 스코프이다.
함수가 정의된 환경과 호출되는 환경은 다를 수 있다. 따라서 렉시컬 스코프가 가능하려면 함수는 자신이 호출되는 환경과는 상관없이 자신이 정의된 환경, 즉 상위 스코프(함수 정의가 위치하는 스코프가 바로 상위 스코프)를 기억해야한다.
✅ 함수는 자신의 내부 슬롯\[[Environment]]에 자신이 정의된 환경, 즉 상위 스코프의 참조를 저장한다.
함수 정의가 평가되어 함수 객체를 생성할 때 자신이 정의된 환경(위치)에 의해 결정된 상위 스코프의 참조를 함수 객체 자신의 내부 슬롯에 저장한다.
함수 내부에서 정의된 함수 표현식은 외부 함수 코드가 실행되는 시점에 평가되어 함수 객체를 생성한다. 이 때 생성된 함수 객체의 내부 슬롯에는 함수 정의가 실행되는 시점, 즉 외부 함수 코드 실행 시점에 실행 중인 실행 컨텍스트의 렉시컬 환경인 외부 함수 렉시컬 환경의 참조가 저장된다.
✅ 함수 객체의 내부 슬롯 [[Environment]]에 저장된 현재 실행중인 실행 컨텍스트의 렉시컬 환경의 참조가 바로 상위 스코프이다.또한 자신이 호출되었을 때 생성될 함수 렉시컬 환경의 "외부 렉시컬 환경에 대한 참조"에 저장될 참조값이다. 함수 객체는 내부 슬롯에 저장한 렉시컬 환경의 참조, 즉 상위 스코프를 자신이 존재하는 한 기억한다.
함수 코드의 평가 순서는 다음과 같다.
- 함수 실행 컨텍스트 생성
- 함수 렉시컬 환경 생성
2-1. 함수 환경 레코드 생성 (변수)
2-2. this 바인딩
2-3. 외부 렉시컬 환경에 대한 참조 설정
this 는 현재 실행되는 코드의 실행 컨텍스트를 말합니다.
'JavaScript > 모던 자바스크립트 딥다이브' 카테고리의 다른 글
36장. 디스트럭처링 할당 (0) | 2023.02.26 |
---|