클로저라는 현상은 런타임 중에 루틴을 만들 수 있는 언어에서 만 발생한다.
루틴(함수)이 생겼을 때, 자유변수가 존재할 수 있는데, 루틴이 그 자유 변수를 참조할 수 있다. 참조하면 해지를 못시킨다. free variables closure. 짧게 말해 closure이다.
JS는 기존에 루틴만이 스코프를 만들어 냈었는데, es6이후에는 블록스코프가 생겼다. 스코프는 클로저를 만드는 행위이다. 그래서 이제는 함수를 만들지 않고 블록만 줘도 스코프가 태어난다. 즉 클로저가 태어난다.
현재의 JS는 중첩되어 있는 클로저 영역을 마구마구 생성할 수 있다. 중괄호를 계속 반복해서 쳐도 클로져가 만들어진다.
예시코드
함수, 블록 스코프로 발생되는 클로저
window.a = 3;
if(a == 3){ // 클로저 생성
const b = 5;
const f1 = v=>{ // 클로저 생성
const c = 7;
if(a + b > c){ // 클로저 생성
return p=>v + p + a + b + c;
}else{ // 클로저 생성
return p=>v + p + a + b;
}
};
}
이 단순한 코드가 내부 메모리에서는 굉장한 클로저 체인을 만들게 되는 것이다.
const a = 3; // 메인플로우 a
if(a == 3){
const a = 5; // 블록스코프 a
const f1 =_=>{
const a = 7; // 루틴 a
console.log(a)
};
}
코드 설명:
메인 플로우에 변수 a가 있다. 근데 블록 스코프안에 또 a가 있다. 근데 루틴안에 또 a가 있다. 이런걸 shadowing이라고 한다. (shadowing은 언어에서 채용하는 경우도 있고 아닌경우도 있음)
shadowing은 층층이 중첩된 클로저가 있는데, 각각의 클로저 상태에서 똑같은 이름의 변수를 소유하고 있을 때 성립한다.
shadowing을 지원하는 언어는 변수명이 겹치면 현재 내가 코드를 실행할 때 가장 가까이 있는 클로저의 이름을 사용하는 것으로 정의 했다.
그래서 위의 코드의 콘솔은 7이 찍힌다. 위의 스코프에도 a가 있어서 자유변수를 참조해 올 수 있지만, 참조해서 이름이 같으면 가장 가까운 클로저 영역의 a를 사용하기 때문에 7를 출력하는 것이다.
shadowing은 언제 쓰는 걸까?
⇒ 네임스페이스를 정의할 때 쓰는 것이다. 이 이름이 내부쪽에서 사용될 때 바깥쪽 자유변수를 오염시키지 않게 하기 위함이다.
중첩된 클로저가 자유변수를 단계에 상관없이 다 가져올 수 있는 언어에서 바깥쪽에 있는 변수를 보호할 수 있는 유일한 방법은 shadowing을 거는 것 뿐이다.
출처: 코드스피츠