클로저(Closure) 이해하기
자바스크립트 모던 딥다이브를 읽으면서 정리한 클로저의 개념
최근 스터디에 소홀하게 되면서, 기술 블로그에 기술 포스팅을 한동안 하지 않았습니다.
집에있던 모던 자바스크립트 Deep Dive를 다시 읽어보면서 책을 읽으면서 몇가지 개념을 정리하던 중
closer
에 대해 기술하려고 합니다.
처음 개발을 시작하며 개발 관련 서적을 읽을 떄,
클로저에 대해서 굉장히 난해한 개념이라고 생각했었고, 실제로 클로저에 대해서 이해하지 못하고 있었습니다.
하지만, 실무에서 React
를 사용하면서 클로저에 대해 이해하고 있는 것을 알았고,
이번 기회에 클로저에 대해 정리하며 이해하고자 합니다.
클로저의 정의
클로저는 함수와 그 함수가 선언된 렉시컬 환경의 조합이다.
이는 MDN에서 제공하는 정의입니다.
Deep Dive에 의하면 정의가 난해해서 무슨 의미인지 잘 와닿지 않는다고 되어있는데, 저 또한 그렇게 생각합니다.
이 정의를 이해하기 위해서는 먼저 함수가 선언된 렉시컬 환경
에 대해 이해해야 합니다.
함수의 렉시컬 환경
📌 렉시컬 환경이란?
쉽게 말해서, 자바스크립트에서 변수를 찾을 때 사용하는 구조입니다.
코드를 **작성한 위치(렉시컬 스코프)**에 따라 변수를 기억하고 접근할 수 있는 환경을 의미합니다.
함수의 렉시컬 환경은 함수가 선언된 문맥에 따라 결정됩니다.
const x = 1;
function outer() {
const x = 10;
function inner() {
console.log(x);
}
inner();
}
outer();
여기서 출력되는 값은 10
입니다.
outer
함수 내부에 있는 inner
함수는 outer
함수의 변수를 참조할 수 있고,
inner
함수 내에는 변수 x
가 없으므로 outer
함수의 변수 x
를 참조하게 됩니다.
이렇게 함수가 선언된 문맥에 따라 결정되는 환경을 렉시컬 환경이라고 합니다.
📌 클로저와 렉시컬 환경
const x = 1;
function outer() {
const x = 10;
function inner() {
console.log(x);
}
return inner;
}
const innerFunc = outer();
innerFunc();
여기서 출력되는 값은 10
입니다.
outer
함수를 호출하면 inner
함수를 반환하고, inner
함수는 outer
함수의 변수 x
를 참조하게 됩니다.
outer
함수를 호출하면 중첩 함수 inner
함수를 반환하고 생명 주기를 마감하게 됩니다.
즉, outer
함수의 실행 컨텍스트가 종료되면 outer
함수의 렉시컬 환경도 소멸됩니다.
하지만, inner
함수는 outer
함수의 변수 x
를 참조하고 있기 때문에,
outer
함수의 렉시컬 환경이 소멸되어도 inner
함수는 여전히 outer
함수의 변수 x
를 참조할 수 있습니다.
이처럼 외부 함수보다 중첩 함수가 더 오래 유지되는 경우, 중첩 함수는 이미 생명 주기가 종료한 외부 함수의 변수를 참고할 수 있는데,
이러한 중첩 함수를 클로저라고 합니다.
리액트에서의 클로저
이러한 클로저는 React
에서 자주 사용되는 개념입니다.
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
위의 코드는 React
에서 자주 사용하는 useState
훅을 사용한 코드입니다.
useState
훅은 handleClick
함수보다 먼저 실행되고, 그 생명주기를 다하게 되지만,
handleClick
함수는 useState
훅의 생명주기를 끝내고 나서도 계속 참조할 수 있습니다.
클릭 이벤트가 발생하면서, handleClick
함수가 실행되고, setCount
함수가 실행되는데,
count
의 초기값은 0이므로, setCount
함수의 인자로 1을 전달하게 됩니다.
이는, handleClick
함수가 실행되면서 클로저가 생성되고, 이 클로저가 count
변수를 참조하게 됩니다.
클로저가 필요한 이유
- 클로저는 상태를 유지합니다.
- 정보 은닉을 통해 외부에서 직접 접근할 수 없도록 보호합니다.
- 메모리의 효율적인 관리가 가능합니다.
function createCounter() {
let count = 0;
return {
increase: function () {
count++;
console.log(count);
},
decrease: function () {
count--;
console.log(count);
},
};
}
const counter = createCounter();
counter.increase();
counter.decrease();
위의 코드에서 count
변수는 createCounter
함수의 지역 변수입니다.
createCounter
함수가 실행되면서 생성된 렉시컬 환경에 저장되고,
createCounter
함수가 종료되면 렉시컬 환경도 함께 소멸됩니다.
하지만, increase
함수와 decrease
함수는 createCounter
함수의 렉시컬 환경에 접근할 수 있고,
외부에서는 count
변수에 직접 접근할 수 없습니다.