클로저 란?
클로저
는 함수와 함수가 선언된 어휘적 환경(Lexical Environment)의 조합입니다.
➡️ 함수와 함수가 정의된 위치의 변수와의 관계를 유지하는 것
함수가 실행될 때, 그 함수의 어휘적 환경이 생성됩니다.
이 어휘적 환경에는 함수 내부에서 사용하는 변수와 해당 변수들의 상위 스코프에 위치한 변수들이 포함됩니다.
해당 함수가 반환될 때, 해당 함수와 그 함수가 선언된 어휘적 환경을 담고 있는 클로저가 생성됩니다.
클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(어휘적 환경)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수입니다.
function outer() {
var x = 1;
function inner() {
console.log(x);
}
inner();
}
outer(); // 1
// ------------------------ //
function outer() {
var x = 1;
inner();
}
function inner() {
console.log(x);
}
outer(); // ReferenceError: x is not defined
outer 함수 내의 inner 함수가 선언되고 호출되었습니다.
이때 outer의 내부 함수인 inner는 외부 함수 outer의 변수 x에 접근할 수 있습니다.
inner는 outer의 내부에서 선언되었기 때문에 inner의 상위 스코프는 outer가 됩니다.
따라서 변수 x에 접근할 수 있기 때문에 x를 출력하게 되는 것입니다.
- inner 함수 스코프 내에서 변수 x을 검색 → x가 없으므로 실패
- inner 함수를 포함하는 외부 함수 outer의 스코프 내에서 변수 x를 검색
➡️ x가 있으므로 출력 가능
만약 inner 함수가 outer 함수의 외부에서 선언되었다면 inner의 상위 스코프는 전역 스코프가 됩니다. 따라서 전역 스코프에 선언된 변수 x가 없기 때문에 참조 에러가 발생하게 됩니다.
function outer() {
var x = 1;
function inner() {
console.log(x);
}
return inner;
}
var innerFunc = outer();
innerFunc(); // 1
outer 함수는 내부 함수인 inner를 반환하고 종료합니다.
➡️ 실행된 이후 콜스택에서 제거
➡️ 따라서 inner에서 x를 접근할 수 없을 것 같음
➡️ 하지만 출력 결과는 1
외부 함수보다 내부 함수가 살아있을 때, 외부 함수가 종료되고 내부 함수가 호출됐을 때, 외부 함수의 지역 변수에 접근할 수 있는 함수를 클로저
라고 부릅니다.
클로저의 활용
모듈 패턴
function counter() {
let count = 0;
return {
increase() {
count++;
console.log(count);
},
decrease() {
count--;
console.log(count);
}
}
}
const count = counter();
count.increase(); // 1
count.decrease(); // 0
counter
함수는 내부에서 count
변수를 선언하고, increase 함수와 decrease 함수를 반환합니다.
이때, 반환된 함수들은 count
변수에 접근할 수 있습니다. counter
함수가 실행될 때 생성된 어휘적 환경은,
반환된 함수가 호출될 때까지 유지됩니다.
따라서 위 코드를 실행하면, increase()
를 호출하면 count가 1 증가한 상태로 출력이 되고,
decrease()
를 호출하면 count가 1 감소한 상태로 출력이 됩니다.
이를 통해, 클로저를 사용하여 함수 외부에서 내부 변수를 유지하고 업데이트할 수 있다는 것을 알 수 있습니다.
데이터를 보존하는 함수
클로저를 응용하면 함수 내부에 선언한 변수와 매개변수에도 접근이 가능합니다.
기존 함수 내부에서 새로운 함수를 리턴하면 클로저로 활용이 가능합니다.
→ 리턴한 새로운 함수의 클로저에 데이터가 보존되는 것입니다.
function createFoodRecipe (foodName) {
const getFoodRecipe = function (ingredient1, ingredient2) {
return `${ingredient1} + ${ingredient2} = ${foodName}!`;
}
return getFoodRecipe;
}
const highballRecipe = createFoodRecipe('하이볼');
highballRecipe('콜라', '위스키'); // '콜라 + 위스키 = 하이볼!'
highballRecipe('탄산수', '위스키'); // '탄산수 + 위스키 = 하이볼!'
커링
커링은 여러 전달인자를 가진 함수를, 함수를 연속적으로 리턴하는 함수로 변경하는 것입니다.
function makeFood(ingredient1) {
return function (ingredient2) {
return function (ingredient3) {
return `음식 완성! 재료: ${ingredient1}, ${ingredient2}, ${ingredient3}`;
}
}
}
const addWater = makeFood('물');
const addSalt = addWater('소금');
const makeDumplingSoup = addSalt('만두'); // 음식 완성! 재료: 물, 소금, 만두
// === const makeDumplingSoup = makeFood('물')('소금')('만두');
const makeRiceCakeSoup = addSalt('떡'); // 음식 완성! 재료: 물, 소금, 떡
console.log(makeDumplingSoup);
console.log(makeRiceCakeSoup);
커링은 함수의 일부만 호출하거나, 일부 프로세스가 완료된 상태를 저장하기에 좋습니다.
'JavaScript' 카테고리의 다른 글
[JavaScript] 프로토타입 (prototype) (0) | 2023.03.15 |
---|---|
[JavaScript] 클래스 (Class) (0) | 2023.03.15 |
[JavaScript] 원시 자료형과 참조 자료형 (0) | 2023.03.15 |
[JavaScript] if와 else if에서의 문제 해결 (0) | 2023.03.15 |
[JavaScript] 조건문과 반복문 (0) | 2023.03.15 |