-
자바스크립트 클로저(Closure), 다시 한번 딱대세요.Java Script & Type Script 2025. 2. 8. 00:29728x90
클로저(Closure)란 무엇인가?
자바스크립트에서 클로저는 함수가 자신이 선언된 환경(렉시컬 스코프)의 변수를 기억하고 참조할 수 있는 기능을 의미합니다. 클로저를 이해하면 함수형 프로그래밍, 비동기 처리, 메모리 관리 등에 대한 깊은 이해를 가질 수 있습니다. 이번 글에서는 클로저에 대한 주요 개념과 활용 방법을 Q&A 형식으로 살펴보겠습니다.
클로저의 생성과 실행 컨텍스트 유지
클로저가 생성될 때 어떤 방식으로 실행 컨텍스트가 유지되나요?
자바스크립트의 실행 컨텍스트는 함수가 호출될 때 생성됩니다. 일반적으로 함수가 종료되면 실행 컨텍스트는 사라지지만, 내부 함수가 외부 함수의 변수를 참조하면 해당 실행 컨텍스트가 GC(가비지 컬렉션)에 의해 제거되지 않고 유지됩니다. 이 때문에 내부 함수는 외부 함수의 변수를 계속 접근할 수 있습니다.
클로저의 변수 참조
클로저가 외부 함수의 변수를 참조할 수 있는 이유는 무엇인가요?
자바스크립트에서는 변수의 스코프가 렉시컬(정적) 스코프를 따릅니다. 즉, 함수가 선언된 시점에서의 스코프 체인을 기억하고 있기 때문에, 내부 함수는 자신이 선언된 위치의 환경을 기억하여 외부 함수의 변수에 접근할 수 있습니다.
클로저 내부에서 참조하는 변수의 값은 언제 결정되나요?
클로저 내부에서 참조하는 변수의 값은 실행 시점에 결정됩니다. 이는 클로저가 외부 변수를 직접 저장하는 것이 아니라 참조하기 때문입니다. 따라서 외부 변수의 값이 변경되면, 클로저 내부에서도 변경된 값을 참조하게 됩니다.
클로저와 메모리 관리
클로저를 사용하면 메모리에 어떤 영향을 미치나요?
클로저는 실행 컨텍스트가 유지되도록 하기 때문에, 외부 함수가 종료되더라도 해당 컨텍스트 내의 변수들이 메모리에 남아 있게 됩니다. 이는 필요하지 않은 경우 메모리 누수를 유발할 수도 있습니다.
클로저가 가비지 컬렉션(GC)에 미치는 영향은 무엇인가요?
일반적으로 실행이 끝난 함수의 변수들은 GC에 의해 정리되지만, 클로저가 외부 변수를 계속 참조하고 있으면 GC가 해당 변수를 제거하지 않습니다. 따라서 클로저를 적절히 해제하지 않으면 불필요한 메모리 사용이 발생할 수 있습니다.
클로저 활용 예제
setTimeout을 사용할 때 클로저를 활용하는 방법은?
function delayedMessage(message, delay) { setTimeout(() => { console.log(message); }, delay); } delayedMessage("Hello, 클로저!", 1000);
위 예제에서 setTimeout 내부의 콜백 함수는 message를 참조하는 클로저를 생성하여 일정 시간이 지난 후에도 값을 유지할 수 있습니다.
루프(for 또는 while) 내에서 클로저를 사용할 때 주의할 점은?
반복문에서 클로저를 사용할 경우 변수의 값이 실행 시점에 결정되므로, 모든 클로저가 최종적으로 반복문의 마지막 값만을 참조할 수 있습니다. 이를 해결하려면 즉시 실행 함수(IIFE)나 let 키워드를 사용해야 합니다.
for (var i = 0; i < 5; i++) { setTimeout((function (index) { return function () { console.log(index); }; })(i), 1000); }
위 코드는 IIFE를 사용하여 각 클로저가 독립적인 index 값을 유지하도록 합니다.
클로저를 사용하여 private 변수를 구현하는 방법
function createCounter() { let count = 0; return { increment: function () { count++; console.log(count); }, getCount: function () { return count; } }; } const counter = createCounter(); counter.increment(); // 1 console.log(counter.getCount()); // 1
위 예제에서 count 변수는 외부에서 직접 접근할 수 없으며, 클로저를 통해서만 접근 가능합니다.
이벤트 리스너에서 클로저를 활용하는 예제
document.getElementById("btn").addEventListener("click", (function () { let count = 0; return function () { count++; console.log(`버튼 클릭 횟수: ${count}`); }; })());
위 예제에서는 클로저를 이용해 클릭 횟수를 저장할 수 있습니다.
클로저를 활용하여 캐싱(Cache) 기능을 구현하는 방법
function createCache() { let cache = {}; return function (key, value) { if (cache[key]) { return cache[key]; } else { cache[key] = value; return value; } }; } const cache = createCache(); console.log(cache("name", "소열")); // "소열" console.log(cache("name")); // "소열"
위 코드는 이미 저장된 값을 다시 계산하지 않고 캐싱된 값을 반환합니다.
클로저의 문제 해결 및 최적화
메모리 누수를 방지하기 위해 클로저 사용 시 고려해야 할 점은?
- 필요하지 않은 클로저를 제거하고 변수 참조를 해제해야 합니다.
- null을 할당하여 참조를 끊어 GC가 메모리를 회수할 수 있도록 합니다.
클로저를 잘못 사용하여 발생할 수 있는 문제에는 어떤 것이 있나요?
- 메모리 누수: 클로저가 불필요하게 유지되면 메모리가 해제되지 않을 수 있습니다.
- 예상치 못한 값 참조: 루프에서 클로저가 변수를 잘못 참조하는 경우 원하는 값이 나오지 않을 수 있습니다.
클로저를 사용하지 않고도 동일한 기능을 구현할 수 있는 방법이 있나요?
- 클로저 대신 클래스를 활용하여 private 변수를 관리할 수 있습니다.
class Counter { #count = 0; increment() { this.#count++; console.log(this.#count); } getCount() { return this.#count; } } const counter = new Counter(); counter.increment();
클로저를 활용한 성능 최적화 방법에는 어떤 것이 있나요?
- 이벤트 리스너에서 클로저 활용: 불필요한 DOM 접근을 줄이고, 클로저를 활용하여 데이터를 보존할 수 있습니다.
- 연산 결과 캐싱: 동일한 계산을 반복하지 않고 캐시된 데이터를 사용할 수 있습니다.
참고해보면 좋을 예시입니다.
https://yalco.notion.site/Closure-f6c3f9c5a5574999ac81b4e6ffd6b61a
Closure | Notion
Hector and Coco
yalco.notion.site
728x90'Java Script & Type Script' 카테고리의 다른 글
[리액트] 카드 정보 입력 UI & 카드번호, 카드유효기간, 생년월일 유효성검사 (0) 2024.06.26 [Next.js] App Router의 신기능, Private Folder & Route Group (Next.js 폴더구조 잡기), File (0) 2024.01.28 [React] 디자인패턴 Custom hook Pattern-UI와 비즈니스로직의 분리에 대하여 (0) 2024.01.20 [React] Tanstack react-query 데이터 리패칭의 네가지 방법 (1) 2023.12.28 [클린코드] 추상화, 관심사의 분리,의존성주입 (Java script version) (0) 2023.07.27