클로저(Closure)
✒️ 2025-05-23 15:07 내용 수정
참고 자료 : mdn web docs closures, inpa tistory 클로저, poiemaweb 클로저
주변 상태에 대한 참조와 함께 묶인 함수의 조합
- 내부 함수에서 외부 함수의 범위에 대한 접근을 제공한다.
- 클로저를 사용해서 클래스의 캡슐화를 할 수 있다.
- Javascript에서는 원래 필드 생성과 private이 없다가 뒤늦게 추가되어 클로저를 사용해서 구현했다.
형태
- 함수가 함수를 반환하는 형태로 작성한다.
- 반환되는 함수는 내부 함수이며, 이 함수가 클로저다.
// 변수를 반환할 때
function test() {
let param = '';
return param;
}
// 함수를 반환할 때
function test2() { // 여기는 외부 함수
var name = "tester"; // 외부 함수의 변수
return function () { // 여기가 내부 함수, 그리고 클로저
console.log(name); // 클로저는 외부 변수를 기억
}
}
특징
- 함수와 함수가 선언된 어휘적 환경(lexical scope)의 조합으로, 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다.
- 다른 몇몇 프로그래밍 언어에서 함수 안의 지역 변수들은 함수가 처리되는 동안에만 지속되지만, Javascript에서는 클로저때문에 함수 처리가 종료되어도 함수 내의 지역 변수에 접근할 수 있다.
- 클로저는 함수가 생성 될 때마다 생성되며, 각각의 클로저는 같은 함수 본문 정의를 공유하지만 서로 다른 맥락(어휘적 환경)을 저장한다.
function test() {
let param = 10; // test의 지역 변수
function fn() { // 내부 함수, 클로저
console.log(param); // 부모 함수의 변수를 사용
}
return fn;
}
let newFn = test();
newFn(); // 10
console.log(param); // Uncaught ReferenceError: param is not defined
// fn은 param에 접근할 수 있지만, 외부에선 param에 직접 접근할 수 없다.
- 함수는 보통 호출 후 동작을 마치면 실행 컨텍스트 스택에서 제거되어 호출될 때 함수의 멤버나 함수 스코프에 대한 정보도 같이 제거되어 더 이상 유효하지 않다.
- 하지만 클로저는 자신이 생성되었을 때의 환경을 기억하기 때문에 자신이 선언되었던 환경 밖에서 호출이 되어도 외부 함수의 스코프에 접근할 수 있다.
function counter() {
var count = 0;
// 클로저는 자신이 선언된 환경을 기억!
function countUp() { // 클로저
count++;
console.log(count);
}
return countUp;
}
// counter는 내부 함수를 반환하고
// 실행 컨텍스트에서 제거됨
// myFunc에는 반환된 내부 함수가 countUp이 담긴다
const myFunc = counter();
// 클로저는 선언된 환경을 기억
// 외부 함수의 스코프였던 count에 대한 기억을 가지고 있다
myFunc(); // 1
myFunc(); // 2
myFunc(); // 3
- 클로저의 특징을 이용하여 외부에서 접근하지 못하는 변수를 관리할 수 있다.
function createUser(email, birth) {
let _email = email; // 함수 내에 선언된 지역함수는 private
const user = {
birth,
get email() {
return _email;
},
set email(address) {
_email = address;
}
}
return user;
}
let user001 = createUser('bbbbbb', '19981024');
console.log(user001._email); // undefined
console.log(user001.email); // bbbbbb
user001.email = 'cccccc'; // set에 바인딩 된 함수로 _email에 접근
console.log(user001.email); // cccccc
user001._email = 'ddddddd'; // 직접 접근하려 한다면 값이 바뀌지 않는다
console.log(user001.email); // cccccc