JAN's History
📚 클로저(Closure)란? 본문
클로저는 하위함수(내부 함수)가 상위 함수보다 더 오래 살아남아, 상위 함수 변수에 접근할 수 있는 것을 의미해요. 일반적으로 함수가 실행되고 나면 그 함수의 Execution Context는 사라지지만, 클로저가 발생하면 상위 함수의 변수나 상태가 메모리에 유지되어 내부 함수에서 계속 사용할 수 있게 됩니다!✨ 이해하기 쉽도록 차근차근 예시를 통해 설명해볼게요!
📌 간단한 클로저 예시
function getNumber() {
var number = 5; // 상위 함수의 변수
function innerGetNumber() { // 하위 함수(내부 함수)
return number; // 상위 함수의 변수에 접근
}
return innerGetNumber;
}
const runner = getNumber(); // getNumber의 실행이 끝났지만...
console.log(runner()); // 내부 함수가 상위 함수의 변수를 기억하고 있어요!
- getNumber 함수가 실행되면 number라는 변수가 생성돼요.
- innerGetNumber 함수는 number에 접근할 수 있어요.
- getNumber 함수는 innerGetNumber 함수를 실행하지 않고 그대로 반환했어요. 사진에서도 Call Stack에 getNumber가 없고 바로 innerGetNumber가 실행이 된 모습을 확인할 수 있죠?
- getNumber의 실행이 끝나도, runner()를 통해 innerGetNumber를 호출하면 number 변수에 여전히 접근할 수 있어요!
⭐ 이게 바로 클로저예요! 하위 함수가 상위 함수의 변수에 접근할 수 있는 "권한"을 가진 상태로 남아있는 것을 말해요.
📌 클로저가 유용한 상황
1. 데이터 캐싱
function cacheFunction() {
var number = 10 * 10; // 오래 걸리는 계산이라고 가정
function innerCacheFunction(newNum) {
return number * newNum; // `number`를 계속 재사용
}
return innerCacheFunction;
}
const runner2 = cacheFunction(); // `number`를 기억하고 있는 `innerCacheFunction` 반환
console.log(runner2(10)); // 1000
console.log(runner2(20)); // 2000
- cacheFunction이 처음 호출될 때, number를 계산하고 메모리에 저장해요.
- 이후 runner2를 통해 innerCacheFunction을 여러 번 호출할 때마다 이미 계산된 number를 사용하니 메모리와 시간을 절약할 수 있어요!
2. 정보 은닉
function Dog(type, size) {
this.type = type; // 공개적으로 접근 가능한 속성
var _size = size; // private 속성 (클로저로 은닉)
this.sayHello = function () {
return `안녕하세요 저는 ${this.type}입니다. 저의 사이즈는 ${_size}입니다.`; // 클로저를 통해 `_size`에 접근
}
}
const pome = new Dog('포메라니안', 'small');
console.log(pome.sayHello()); // '안녕하세요 저는 포메라니안입니다. 저의 사이즈는 small입니다.'
console.log(pome.type); // '포메라니안'
console.log(pome._size); // undefined, 외부에서 직접 접근 불가
- Dog 객체를 통해 sayHello 메서드에서만 _size를 사용할 수 있고, 외부에서는 직접 _size에 접근할 수 없어요.(this가 없기 때문)
- 이를 통해 데이터를 은닉하고, 외부에서 함부로 객체의 상태를 변경할 수 없게 만들 수 있어요.
🛠 중요한 포인트: 왜 클로저를 사용해야 할까?
1. 정보 은닉과 캡슐화
- 클로저를 사용하면 외부에서 내부 데이터에 직접 접근하는 것을 방지할 수 있어요.
- 클래스에서의 private 같은 역할을 자바스크립트에서 흉내 낼 수 있죠.
2. 데이터 캐싱과 메모리 관리
- 클로저를 이용해 이전에 계산된 데이터를 저장하고 재사용함으로써, 성능 향상이 가능해요.
- 한 번 계산된 결과를 메모리에 기억해두고 여러 번 사용할 수 있어요.
⭐ 혼란스러운 부분: 클로저가 안 되는 경우는?
아래 코드를 볼게요:
function cacheFunction2() {
var number = 99;
function increment() {
number++;
return number;
}
return increment; // 실행하면 클로저가 안됨
}
const runner3 = cacheFunction2();
console.log(runner3()); // 100
console.log(runner3()); // 101
- 이 코드에서는 number를 계속 증가시킬 수 있고, 이는 클로저가 잘 작동하는 예시예요.
하지만 만약 내부 함수가 실행되지 않고 바로 반환된다면 클로저가 제대로 작동하지 않아요.
function cacheFunction3() {
var number = 99;
function increment() {
number++;
return number;
}
return increment(); // 클로저가 아님, 함수를 실행해버렸기 때문!
}
console.log(cacheFunction3()); // 100
console.log(cacheFunction3()); // 100
- 이 경우엔 클로저가 아니라 함수를 실행한 결과를 반환하므로 클로저의 특성이 사라집니다.
💡 요약
- 클로저는 하위 함수가 상위 함수의 변수에 계속 접근할 수 있는 것.
- 데이터 캐싱, 정보 은닉 등에 유용해요.
- 클로저를 잘 활용하면 메모리 관리를 효율적으로 할 수 있고, 코드의 안정성을 높일 수 있어요! 😊
'Javascript' 카테고리의 다른 글
📚 콜백 지옥, 프로미스, 그리고 async/await까지 (1) | 2024.11.07 |
---|---|
📚 자바스크립트의 비동기 프로그래밍 (0) | 2024.11.05 |
JavaScript의 Execution Context Stack (2) | 2024.10.31 |
자바스크립트에서 this 키워드 이해하기 (0) | 2024.10.29 |
프로토타입 체인과 객체 상속의 이해 (1) | 2024.10.26 |