-
Notes from reading 🔖 You Don't Know JS Yet - 12JavaScript 2026. 5. 17. 17:28
### 파트2 - Chapter 7 클로저 사용법
- 클로저또한 최소 노출의 원칙 (POLE)을 기반으로 한다.
- 클로저를 사용하면, 변수를 외부 스코프에 두는 대신에 더 제한된 스코프로 캡슐화가 가능하다.
- 이를 통해서 함수 내부에서 함수 밖 해당 변수에 계속 접근이 가능하여 변수를 더 넓은 범위에서 사용 가능
- 클로저를 통해 참조된 스코프 변수를 기억하기 때문
- 클로저는 함수 안에서만 일어나는 함수의 동작. 함수를 다루지 않으면, 클로저는 적용 X
- 객체, 클래스는 클로저를 가질 수 없다. 함수만 가능
- 화살표 함수도 클로저가 있다.
- 작은 화살표 함수를 사용하더라도, 클로저가 생성될 수 있다.
- 클로저는 단순 함수의 코드에 의해 정의되는 단일 렉시컬 정의가 아니라, 함수 인스턴스에 따라 다르게 생성된다.
- 인스턴스가 생성될 때 마다 각각 인스턴스는 다른 독립적인 클로저를 가진다는 의미인듯
- 실제 클로저의 동작은 실행 시점에 함수 인스턴스에 따라 달라진다.

- 클로저는 스냅샷이 아닌 라이브 링크이다. (생성되는 시점에 고정되는 것이 아니라는 뜻)
- 라이브 링크이기 때문에, 수정/재할당이 가능하다 -> 클로저 함수가 많이 쓰이는 이유이기도 함.
- 클로저의 외부 스코프는 꼭 함수 스코프이지 않아도 된다. (일반적으로 함수 스코프이긴 함)
- 내부 함수를감싸는 외부 스코프가 존재하기만 해도 클로저가 됨
- 클로저는 특정 시점의 값을 저장하는 그런 기능이 아님!
- 콜백을 사용할 때 클로저는 자주 사용된다. (Ajax, 이벤트 등)
- 클로저는 비동기적인 환경에서도 변수에 접근할 수 있게 해준다.
- 클로저 -> 관찰 가능성 O. 하지만, 작성한 프로그램에서 관찰이 X 하면 ? 괜찮지 않다.
- 전역 변수에 접근할 때가 그 예시
- 변수가 존재하기만 하고, 한 번도 해당 변수에 접근하지 않는 경우에 클로저 관측 X
- 함수가 호출되지 않을때도 그렇다.
클로저의 정의 ✨
- 반드시 함수와 연관됨
- 외부 스코프 변수를 하나 이상 참조해야 함
- 참조하려는 변수가 있는 스코프 체인의 다른 분기에서 함수를 호출해야 함
=> 관찰 가능성
/** * ============================================ * Closure (클로저) 완전 정리 예제 * ============================================ * * 이 파일 하나로 아래 내용을 모두 설명: * * 1. 기본 클로저 * 2. 클로저는 스냅샷이 아닌 라이브 링크 * 3. 함수 인스턴스마다 다른 클로저 * 4. 화살표 함수 클로저 * 5. 객체 자체는 클로저가 아님 * 6. 비동기 + 콜백에서의 클로저 * 7. 관찰 가능성(observability) * 8. 전역 변수와 클로저 차이 */ /* ========================================================= * 1. 가장 기본적인 클로저 * ========================================================= */ console.log("===== 1. 기본 클로저 ====="); function outer() { // outer 함수의 지역 변수 let count = 0; // inner 함수는 outer 스코프의 count를 참조 function increase() { count++; console.log("count:", count); } // increase 함수 반환 return increase; } // outer 실행 종료 // 하지만 increase는 count를 계속 기억함 const fn = outer(); fn(); // 1 fn(); // 2 fn(); // 3 /** * 핵심: * * 원래라면 outer 종료 후 count는 사라져야 함. * 하지만 increase 함수가 count를 계속 참조하고 있으므로 * JS 엔진이 메모리에서 유지함. * * 이것이 클로저. */ /* ========================================================= * 2. 클로저는 스냅샷이 아니라 라이브 링크 * ========================================================= */ console.log("\n===== 2. 라이브 링크 ====="); function liveLinkExample() { let value = 1; function print() { console.log("value:", value); } function change() { value = 999; } return { print, change, }; } const live = liveLinkExample(); live.print(); // 1 // 외부 변수 수정 live.change(); live.print(); // 999 /** * 만약 클로저가 "값 복사"였다면: * * 1 * 1 * * 이 출력되어야 함. * * 하지만 실제로는: * * 1 * 999 * * 이 출력됨. * * 즉 클로저는 값을 복사하는 게 아니라 * "살아있는 변수 참조(live reference)" 를 유지함. */ /* ========================================================= * 3. 함수 인스턴스마다 서로 다른 클로저 * ========================================================= */ console.log("\n===== 3. 함수 인스턴스마다 다른 클로저 ====="); function makeCounter() { let count = 0; return function () { count++; console.log(count); }; } // 각각 새로운 함수 인스턴스 생성 const counter1 = makeCounter(); const counter2 = makeCounter(); /** * counter1 과 counter2 는 같은 코드로 만들어졌지만 * 서로 다른 count를 가진다. * * 즉 makeCounter() 호출 때마다 * 새로운 클로저 생성. */ counter1(); // 1 counter1(); // 2 counter2(); // 1 counter2(); // 2 /* ========================================================= * 4. 화살표 함수도 클로저 가능 * ========================================================= */ console.log("\n===== 4. 화살표 함수 클로저 ====="); function arrowClosure() { let name = "citron"; // 화살표 함수도 외부 스코프 기억 가능 return () => { console.log(name); }; } const arrowFn = arrowClosure(); arrowFn(); /** * 클로저는 함수 종류와 관계없음. * * 가능: * - 일반 함수 * - 함수 표현식 * - 화살표 함수 */ /* ========================================================= * 5. 객체 자체는 클로저가 아님 * ========================================================= */ console.log("\n===== 5. 객체와 클로저 ====="); // 단순 객체 const normalObject = { value: 10, }; console.log(normalObject.value); /** * 이건 클로저가 아님. * * 이유: * - 함수 없음 * - 렉시컬 스코프 캡처 없음 */ // 실제 클로저 예제 function objectWithClosure() { let secret = "hidden"; return { getSecret() { return secret; }, }; } const obj = objectWithClosure(); console.log(obj.getSecret()); /** * 여기서 클로저를 만드는 건 객체가 아니라 * getSecret 함수. */ /* ========================================================= * 6. 비동기 + 콜백에서의 클로저 * ========================================================= */ console.log("\n===== 6. 비동기 콜백 ====="); function fetchData() { let data = "important data"; // setTimeout 콜백은 나중에 실행됨 setTimeout(() => { // 하지만 data 접근 가능 console.log(data); }, 1000); } fetchData(); /** * fetchData 함수는 이미 끝났는데 * 1초 뒤에도 data 접근 가능. * * 이유: * 콜백 함수가 data를 클로저로 기억하기 때문. * * 실무에서 가장 흔한 클로저 사용 사례: * - 이벤트 핸들러 * - Ajax * - Promise * - setTimeout * - React Hook */ /* ========================================================= * 7. 관찰 가능성(observability) * ========================================================= */ console.log("\n===== 7. 관찰 가능성 ====="); function observableClosure() { let x = 10; return function () { console.log(x); }; } const observable = observableClosure(); observable(); /** * outer 함수 종료 후에도 x 접근 가능. * 우리가 실제로 확인 가능. * * => 관찰 가능한 클로저 */ // 관찰 불가능한 예시 function notObservable() { let y = 20; function inner() { console.log(y); } // inner 호출 안 함 // 반환도 안 함 } /** * 여기서는 클로저 존재 여부를 * 외부에서 관찰할 수 없음. * * 실질적인 의미가 거의 없음. */ /* ========================================================= * 8. 전역 변수와 클로저 차이 * ========================================================= */ console.log("\n===== 8. 전역 변수 ====="); let globalValue = 10; function printGlobal() { console.log(globalValue); } printGlobal(); /** * 기술적으로 스코프 체인을 사용하긴 함. * * 하지만 보통 이런 경우를 * 대표적인 클로저라고 부르진 않음. * * 클로저의 핵심은: * * "이미 종료된 외부 함수의 변수를 * 계속 기억하는 것" */ /* ========================================================= * 9. 최종 정리 * ========================================================= */ /** * 클로저의 핵심 조건: * * 1. 함수가 존재해야 함 * 2. 외부 스코프 변수를 참조해야 함 * 3. 함수가 다른 스코프에서 실행되어야 함 * 4. 외부 함수 종료 후에도 변수 접근 가능해야 함 * * 한 줄 요약: * * "함수가 자신이 생성된 당시의 스코프를 기억하는 것" */'JavaScript' 카테고리의 다른 글
Notes from reading 🔖 You Don't Know JS Yet - 11 (0) 2026.05.09 함수 파라미터 기본값, 왜 undefined는 되고 null은 안 될까? (0) 2026.03.14 Notes from reading 🔖 You Don't Know JS Yet - 10 (1) 2026.01.17 Notes from reading 🔖 You Don't Know JS Yet - 9 (0) 2026.01.03 Notes from reading 🔖 You Don't Know JS Yet - 8 (0) 2025.12.27