JS를 초반에 처음 배웠을땐 클로저라는 개념에 대해 명확히 이해를 하지 못했다.
JS를 공부한다면 필히 한번 쯤은 들어본다는 클로저! 나 또한 정확히 클로저에 대해서 설명해 보라고 하면 정말 설명을 못하겠다..다시 한번 정리를 해보려고 한다.
클로저가 어떤 의미인지 다시 한번 꼼꼼히 살펴보았다!
클로저는 함수와 함수가 선언된 어휘적 환경(lexical scoping)의 조합이다.
출처:https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures
도대체 이게 무슨 말이지..? 진짜 어렵게도 적어놓네..
강의를 보면서 정리를 해보았다..
기본적으로 자바스크립트는 실행 컨텍스트 라는 개념이 존재한다.
아래의 간단한 코드를 보자.
<script>
let l0 = "l0";
function fn1(){
let l1 = "l1";
console.log(l0,l1);
}
fn1();
</script>
아래의 코드에서는 당연히 스크립트 스코프에 변수 l0의 값이 담겨 있을 것 이며, 다음에 fn1() 함수를 실행시켜서 변수 l1의 값이 담길 것 이다.
아래의 사진처럼 말이다.
여기서 질문! 만약의 코드가 아래의 코드와 같다면 fn2() 함수의 콘솔이 정상적으로 찍힐까?
<script>
let l0 = "l0";
function fn1(){
let l1="l1";
console.log(l0,l1);
fn2();
}
function fn2(){
let l2="l2";
console.log(l0,l1,l2);
}
fn1();
</script>
콘솔에서는 변수 l1 값을 찾지 못하여 l1 is not defined 에러가 발생한다.
왜 그럴까?? 뭔가 체감 상으로는 fn1() 함수 안에서 fn2() 함수를 실행 시키니까 서로 값이 공유되고 그럴 거 같은데 값을 공유하지 못하네??
왜냐하면 이 둘은 다른 로컬 스코프를 참조 하고 있기 때문이다.
코드에서도 보이다 시피 변수 l1 값은 fn1() 함수 안에 있다. 즉 로컬 스코프 이긴 하지만 다른 함수를 바라보고 있는 것이다. 제일 첫번째 코드와 두번째 코드를 비교해 보았을 때 로컬 안에 있는 변수의 값이 서로 다르게 적용되어 있다는 것을 알 수 있다. l1의 값을 아무리 찾아보려고 해도 값이 없기 때문에 당연히 값이 정의가 되지 않은 것이다!
즉 여기서 중요한 사실을 하나 알 수 있게 되었다.
자바스크립트 함수의 유효 범위는 그 함수가 어디에서 실행 되었느냐? 가 아니라 어디에 정의 되었는가? 에 따라서 달라진다는 사실이다.
그렇다면 어떻게 해야 변수 l1 값을 가져 올 수 있을까??
방금 중요한 개념 중에 하나가 자바스크립트 함수의 유효 범위는 어디에 정의 되었는지에 따라서 정해 진다고 했다. 그렇다면!
fn2() 함수를 fn1() 함수 안으로 이사 시켜보자.
fn1()함수를 실행함과 동시에 fn1()함수 안에다가 fn2() 함수를 정의하게 되면?
<script>
let l0 = "l0";
function fn1(){
function fn2(){
let l2="l2";
console.log(l0,l1,l2);
}
let l1="l1";
console.log(l0,l1);
fn2();
}
fn1();
</script>
이런 상황에서는 정상적으로 콘솔이 출력 될까??
정상적으로 출력 된다. 디버깅을 통해 확인 해 보자.
사진을 보면 중간에 닫기(Closure)가 생긴 것을 볼 수 있다.
따라서 실행 컨텍스트의 개념에 따라 설명을 해보자면 console.log(l0,l1,l2); 가 실행 될 때 변수 l0은 스크립트 스코프 에서 찾을 수 있고,변수 l1은 클로저 라는 스코프에서 찾아 볼 수 있다. 변수 l2는 로컬 스코프를 참조하여 값을 불러 낼 수 있게 되는 것이다.
그렇다면 lexical scoping 이라는 어려운 말은 무슨 말이냐?
즉 자바스크립트의 클로저는 함수가 어디에 정의 되었는가를 기준으로 클로저를 정의한다. 함수를 정의 할 때 함수를 호출 하듯이 막 동적으로 아무 곳 에서 정의를 할 수 있는가? 아니지 않는가? 따라서 클로저는 굉장히 정적인 것이다. 그래서 자바스크립트는 정적인 스코프 즉 영어로 lexical Scope 라는 용어를 쓰는 것 이다.
즉 정리하자면 함수를 함수 안에 정의 하면 그 함수의 부모 함수 스코프에 접근 할 수 있도록 하는 것이다.