자바스크립트는 static scope
로 동작하는 정적 스코프의 특징을 가지고 있으며,
이와 관련해 만들어진 것이 closure이다
이에 대한 원리를 살펴보자
<script>
let l0 = 'l0';
function fn1(){
let l1 = 'l1';
console.log(l0, l1 ) ;
}
fn1(); // l0, l1
</script>
fn1 () 의 지역 변수로 l1이 존재하고, 상위 스코프인 전역 컨텍스트에 l0가 존재하므로 이를 참조할 수 있다
<script>
let l0 = 'l0';
function fn2(){
let l2 = 'l2';
console.log(l0, l1, l2);
//Uncaught ReferenceError : l1 is not defined
}
function fn1( ){
let l1 = 'l1';
fn2();
}
</script>
fn2()에서는 l1을 참조할 수 없다.
왜냐하면, f2의 지역변수로 l2만이 존재하며, fn2의 상위 스코프는 전역 스코프이므로, 해당 컨텍스트에는 l0만이 존재하므로 l1의 선언을 참조할 수 없다.
이렇게 어떤 함수가 있을떄, 함수는 어디에서 호출했는지가 아닌 어디에
정의
하였는가가 이를 결정한다고 볼 수 있다.
이를 정적 스코핑이라고 한다
static scope === lexical scope
자바스크립트의 특성이다
클로저는 이러한 함수의 특성을 활용한 것으로 볼 수 있다
다음 예제를 보자
<script>
let l0 = 'l0';
function fn1(){
function fn2( ){
let l2 = 'l2';
console.log(l0, l1, l2); //l0, l1, l2
}
let l1 = 'l1';
console.log(l0,l1); //l0, l1
fn2();
}
</script>
fn2( )의 스코프는 Local, Closure, Script로 구성되며,
Closure안에 l1이 존재한다.
<script>
let l0 = 'l0';
function fn1(){
function fn2( ){
function f3(){
let l3 = 'l3'
console.log(l0,l1,l2,l3) //l0, l1, l2, l3
}
let l2 = 'l2';
console.log(l0, l1, l2); //l0, l1, l2
}
let l1 = 'l1';
console.log(l0,l1); //l0, l1
fn2();
}
</script>
fn3( )의 Local -> Closure (fn2()) -> Closure (fn3()) -> Script로 탐색하여 진행된다
<script>
function 더하기함수공장(초기값){
function 덧셈(숫자 ){
return 초기값 + 숫자;
}
return 덧셈
}
let 더하기1 = 더하기함수공장(1)
console.log(더하기1(1)) //2
console.log(더하기1(2)) //3
let 더하기2 = 더하기함수공장(2)
console.log(더하기2(1)) //3
console.log(더하기2(2)) //4
</script>
덧셈이라는 함수를 더하기함수공장안에서 호출한 것이 아니라, 외부에서 접근한 것이다
이렇게 정의된 함수 내부에서가 아닌 부모 함수만이 동봉되어서 가지고 있으며,
이 함수를 반환받은 변수에 접근가능한 것이 클로저이다