⚠️
클로저
는 자바스크립트 고유의 개념이 아니다!
함수를일급 객체
취급하는 함수형 프로그래밍 언어(ex 하스켈, 리스프, 얼랭, 스칼라 등)에서 사용되는 중요한 특성이다.
❓ 일급 객체
: 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체
클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다.
무슨 말인지 모르겠다.
함수가 선언된 렉시컬 환경이 뭔지 살펴보자
const x = 1
function outerFunc() {
const x = 10;
function innerFunc() {
console.log(x); // 10
}
innerFunc();
}
outerFunc();
여기서 중첩 함수 innerFunc()의 상위 스코프는 외부 함수 outerFunc()의 스코프이기 때문에 innerFunc에서도 outerFunc의 x 변수에 접근할 수 있다.
const x = 1;
function outerFunc(){
const x = 10;
innerFunc();
}
function innerFunc(){
console.log(x); //1
}
outerFunc();
innerFunc가 outerFunc 내부에서 호출하더라도 outerFunc의 x 변수에는 접근할 수 없다.
-> 자바스크립트는 렉시컬 스코프
를 따르는 프로그래밍 언어이기 때문
자바스크립트 엔진은 함수를 어디서 호출했는지가 아니라 함수를 어디에 정의했는지에 따라 상위 스코프를 결정하는데 이를 렉시컬 스코프(정적 스코프)라고 한다.
const x = 1;
function foo() {
const x = 10;
bar();
}
function bar() {
console.log(x);
}
foo();
bar();
foo() bar() 모두 전역에서 정의된 전역 함수다. 어디서 정의했느냐 에 따라 상위 스코프가 결정되기 때문에 전역 함수 -> 상위 스코프도 전역
따라서 "함수의 상위 스코프를 결정한다" 라는 것은
"렉시컬 환경의 외부 렉시컬 환경에 대한 참조를 저장할 참조값을 결정한다!" 라는 것과 같다.
함수가 정의된 위치와 호출되는 위치는 다를 수 있다.
렉시컬 스코프가 가능하려면? 함수는 호출되는 위치와는 상관 없이 정의된 위치의 상위 스코프를 기억해야 한다.
-> 함수는 자신의 내부 슬롯 [[Environment]]에 자신이 정의된 환경, 상위 스코프의 참조를 저장한다.
const x = 1;
//1번
function outer() {
const x = 10;
const inner = function () {
console.log(x) //2번
};
return inner;
}
const innerFunc = outer(); //3번
innerFunc(); //4번 10
outer 함수를 호출하면 중첩 함수 inner를 반환하고 생명주기(라이프사이클)을 마감한다. -> 호출 후 실행컨텍스트 스택에서 제거된다.
이때 outer 함수의 지역변수 x와 변수 값 10을 저장하고 있던 outer 함수의 실행 컨텍스크가 제거되었으니 outer 함수 지역 변수 x 또한 생명주기를 마감한다. 따라서 outer 함수의 지역변수 x는 더는 유효하지 않게 되니 x 변수에 접근할 수 없을 것 같지만..? 4번 innerFunc함수를 실행하면 outer험수의 지역변수 x값인 10이 호출된다.
외부 함수보다 중첩 함수가 더 오래 유지되는 경우 중첩 함수는 이미 생명 주기가 종료한 외부 함수의 변수를 참조할 수 있다. 이런 중첩 함수를 클로저 라고 부른다