[JavaScript] 클로저(Closure)
[JavaScript] 클로저(Closure)
클로저(Closure) 는
“함수가 만들어질 때의 스코프(변수 환경) 를 기억해서, 함수 바깥에서 실행돼도 그 변수를 계속 접근할 수 있는 것”을 말한다.
즉, 함수 + 그 함수가 참조하는 외부 변수(렉시컬 환경) 가 함께 묶여서 살아있는 상태가 클로저다.
왜 ‘기억’이 가능한가?
자바스크립트 함수는 실행될 때마다 내부에서 필요한 변수를 찾는다.
1) 먼저 자기 스코프에서 찾고
2) 없으면 바깥(상위) 스코프로 올라가며 찾는다(스코프 체인).
이때, 함수가 바깥 변수를 참조하고 있다면, 그 바깥 변수는 가비지 컬렉션(GC) 대상이 되지 않고 유지된다.
그래서 함수가 나중에 호출돼도 그 변수를 계속 쓸 수 있다.
가비지 컬렉션(GC): 어디에서도 참조되지 않아 도달 불가능한 값을 자동으로 메모리에서 정리하는 기능
가장 기본 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function makeCounter() {
let count = 0;
return function () {
count += 1;
return count;
};
}
const counter = makeCounter();
counter(); // 1
counter(); // 2
counter(); // 3
클로저를 쓰는 대표 이유 3가지
1) 상태(State) 캡슐화 (외부에서 직접 못 건드리게)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function createUser(name) {
let point = 0;
return {
getName() {
return name;
},
addPoint(v) {
point += v;
},
getPoint() {
return point;
},
};
}
const user = createUser("test");
user.addPoint(10);
user.getPoint(); // 10
- point는 외부에서 직접 접근 불가, 함수로만 접근 가능
- 안전하게 상태를 관리할 수 있다.
2) 함수 팩토리(함수 생성기)
1
2
3
4
5
6
7
8
9
10
11
function multiplyBy(n) {
return function (x) {
return x * n;
};
}
const double = multiplyBy(2);
const triple = multiplyBy(3);
double(10); // 20
triple(10); // 30
n을 기억하는 함수들을 쉽게 만들 수 있음
3) 콜백/이벤트에서 “원래 값” 유지
1
2
3
4
5
6
7
function greetLater(name) {
setTimeout(() => {
console.log(`안녕, ${name}!`);
}, 1000);
}
greetLater("test"); // 1초 뒤: "안녕, test!"
setTimeout은 나중에 실행되지만 콜백이 name을 기억(클로저)해서 출력 가능
클로저의 단점(주의점)
1) 메모리 유지가 길어질 수 있음
클로저가 외부 변수를 참조하면, 그 변수는 계속 살아있다.
큰 데이터를 참조하는 클로저를 오래 유지하면 메모리를 더 쓸 수 있다.
1
2
3
4
5
6
7
8
let handler = (() => {
const big = new Array(1000000).fill("x");
return () => big.length;
})();
handler(); // 사용
handler = null; // 더 이상 필요없으면 참조 끊기 (GC 가능해짐)
2) “값이 고정된 줄 알았는데” 같이 변하는 경우
클로저는 값을 복사하는 게 아니라 변수(참조) 를 잡는다.
그래서 바깥 변수가 바뀌면 클로저 결과도 바뀐다.
1
2
3
4
5
6
let x = 1;
const f = () => x;
f(); // 1
x = 10;
f(); // 10
마무리 정리
- 클로저 = 함수가 바깥 스코프 변수를 “기억”하고 계속 접근 가능한 상태
- 장점: 상태 캡슐화, 함수 생성, 콜백에서 값 유지
- 주의: 메모리/예상 못한 참조 공유
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.