안녕하세요.
오늘은 Javascript 개발을 하다 보면 한 번쯤은 들어봤을 클로저(Closure)에 대해 알아보도록 하겠습니다.
클로저란?
자바스크립트에서 함수가 외부 범위의 변수를 기억하는 것처럼 보이는 현상을 접한 적이 있나요? 클로저(Closure)는 자바스크립트에서 외부 함수가 실행된 후에도 외부 범위에 대한 접근 권한을 유지하는 함수입니다. 이는 내부 함수가 외부 함수 범위의 변수를 "닫아서" 가비지 컬렉션(Garbage collection)으로부터 보호하는 것을 의미합니다.
들어가기 전에 알아야 할 자바스크립트 지식
렉시컬 스코핑 (Lexical Scoping)
렉시컬 스코핑은 변수의 접근성을 코드 내 위치에 따라 결정하는 방식을 뜻합니다.. 이 정적 접근 방식은 복잡한 코드 기반에서 예측 가능한 동작을 보장하고 잠재적인 혼란을 방지합니다.
함수 유효범위 (Function Scope)
각각의 자바스크립트 함수는 함수 내에 선언된 로컬 변수를 보관하는 자체 렉시컬 환경을 생성합니다. 이러한 변수는 함수 내에서만 접근 가능하며 외부에서 직접 수정할 수 없습니다.
변수 유효범위 체인 (Variable Scope Chain)
함수가 선언된 범위 외부의 변수에 접근해야 하는 경우, 해당 함수는 부모 함수의 범위에서 변수를 검색합니다. 현재 함수에서 시작하여 호출 스택을 거슬러 올라가는 범위 체인을 변수 유효범위 체인(Variable Scope Chain)이라고 합니다.
클로저의 동작방식
함수가 다른 함수 내에 정의되면 내부 함수는 외부 함수의 변수에 접근할 수 있습니다. 이 접근은 내부 함수가 변수를 유지하기 위해 외부 함수의 참조를 유지함으로써 가능해집니다.
예제와 함께 이해하는 클로저
간단한 예제와 함께 클로저를 이해해 보도록 하겠습니다.
function outerFunction() {
let message = "안녕하세요, ";
function innerFunction(name) {
return message + name;
}
return innerFunction;
}
let sayMyName = outerFunction();
console.log(sayMyName("Poki"));
안녕하세요, Poki
내부 함수 innerFunction은 외부 함수 outerFunction에서 정의된 message 변수에 접근할 수 있습니다.
다른 예제도 한번 보겠습니다.
function createCounter() {
let count = 0;
return function add() {
count = count + 1;
return count;
};
}
const counter1 = createCounter();
const counter2 = createCounter();
console.log(counter1());
console.log(counter1());
console.log(counter2());
1 2 1
createCounter함수는 지역 변수 count를 생성하고 내부 함수 add를 반환합니다. 이 내부 함수는 반환되더라도 외부 범위의 count 변수에 대한 참조를 유지합니다. counter1 및 counter2 가 각각 고유한 count 변수를 유지합니다.
클로저의 장점
이전의 예제를 보면서 조금은 이해가 되셨나요? 그럼 이 클로저를 왜 써야 하는지 장점에 대해 알아보겠습니다.
데이터 캡슐화 및 상태 관리
함수 내에 독립적인 변수를 만들 수 있어 외부에서 실수로 또는 의도적으로 수정되는 것을 방지합니다. 이는 데이터 캡슐화를 통해 민감한 정보를 보호하고 데이터 무결성을 보장합니다. 또한 함수 내 상태를 관리하여 함수 호출 간에 값을 유지할 수 있습니다.
모듈화 및 코드 재사용성
독립적인 변수와 함수를 클로저로 캡슐화하여 더 깨끗한 코드 구성을 위한 재사용 가능한 모듈을 만들 수 있습니다. 이러한 방식은 유지 보수성을 향상시키고 코드 중복을 줄이며 구조화된 코드 기반을 구축하는데 도움을 줍니다.
클로저의 단점
클로저의 장점만 본다면 자바스크립트 개발자라면 꼭 사용해야 하는 방식이라 보이는데, 정말 그럴까요? 단점을 확인해 보도록 하겠습니다.
메모리 누수 (Memory leaks)
클로저가 큰 Object 또는 DOM 요소에 대한 참조를 하는 경우 해당 메모리가 더 이상 필요하지 않더라도 가비지 컬렉터가 해당 메모리를 회수하지 못할 수 있습니다. 클로저는 적절하게 관리되지 않으면 회수하지 못한 메모리가 조금씩 누적되면서 메모리 누수를 발생시킬 수 있습니다. 이를 방지하기 위해서는 클로저가 더 이상 필요하지 않을 때 클로저를 해제하는 것이 중요합니다.
성능 문제
클로저를 생성하는 것은 외부 범위의 변수를 기억하는 것을 의미하며, 이는 성능에 영향을 줄 수 있습니다. 특히 클로저 또는 중첩된 클로저를 많이 사용하는 상황에서는 성능에 미치는 영향을 확인해야 합니다.
FAQ
클로저는 어떤 상황에서 일반적으로 사용되나요?
동적 데이터가 있는 이벤트 리스너
DOM 요소에 이벤트 리스너를 연결할 때 해당 요소와 관련된 데이터에 액세스해야 하는 경우가 많습니다. 이벤트 리스너 함수 내에 클로저를 만들어 요소 데이터를 참조하면 여러 요소가 동일한 이벤트 처리기를 공유하더라도 올바른 정보에 액세스 할 수 있습니다.
익명함수
함수를 다른 함수로 래핑 하여 익명함수 내 변수의 범위를 제어하고 독립적인 변수와 Logic을 만들 수 있습니다. 이 패턴은 종종 데이터 초기화, 모듈 생성 및 네임스페이스 관리에 사용됩니다.
비동기 작업
비동기 작업이 완료된 후 데이터에 액세스 하거나 작업을 수행해야 하는 상황이 발생할 수 있습니다. 필요한 데이터와 로직을 참조하는 클로저를 만들면 비동기 작업이 완료된 후 종료될 때 올바른 데이터를 사용할 수 있습니다.
클로저는 일반적인 자바스크립트 함수와 어떻게 다른가요?
클로저는 외부 함수가 실행된 후에도 외부 범위에 대한 접근 권한을 유지하는 반면, 일반 함수는 그렇지 않습니다.
자바스크립트에서 클로저를 사용할 때 어떻게 사용하면 좋은가요?
불필요한 클로저 생성을 피하고, 클로저가 더 이상 필요하지 않을 때 클로저를 해제하여 메모리 누수를 방지하고, 성능에 대한 영향을 신중하게 고려해야 합니다.
결론
클로저는 함수에 "기억"을 제공하는 강력한 개념입니다. 렉시컬 스코핑과 변수 범위 체인을 활용하여 클로저는 데이터 캡슐화, 상태 관리, 코드 모듈화를 가능하게 합니다. 또한 클로저를 이해하는 것은 코드 중복을 줄이고 유지 보수면에서 효율적인 자바스크립트 코드를 작성하는 데 필수적이라고 생각합니다.
마치며
자바스크립트를 공부하면서 쉽게 지나칠 수 있는 개념인 클로저에 대해 알아보았습니다. 저 또한 개발하면서 너무나도 가볍게 생각했던 개념이었지만 상세하게 알아갈수록 핵심적인 개념이 아닐까 생각이 들었습니다. 이 개념을 완벽하게 이해한다면 새로운 수준의 코딩을 할 수 있을 것 같다는 생각이 들었습니다.
긴 글 읽어주셔서 감사합니다.
레퍼런스
오타 혹은 잘못된 내용이 있다면 부담 없이 댓글로 알려주세요 :)
문장을 다듬는데 ChatGPT의 도움을 받았습니다.
'Web > 지식창고' 카테고리의 다른 글
[Web/Javascript] 프로토타입 (Prototype)에 대해서 (0) | 2024.06.17 |
---|---|
[Web/Javascript] this와 call(), apply(), bind() 이해하기 (0) | 2024.06.17 |
[Web/Javascript] var, let, const 알아보기 (0) | 2024.06.17 |
[Web] 모바일 기기 Chrome DevTools 실시간 확인방법 (0) | 2024.06.17 |
[Web] REST API에 대해 (0) | 2024.06.17 |