클로져(Closure)
1. 클로저(Closure)란
클로저(closure)는 함수와 그 함수가 선언되었을 때 렉시컬 환경(lexical environment)과의 조합입니다.
스코프(scope)는 함수를 호출할 때가 아니라 함수를 어디에 선언하였는지에 따라 결정됩니다.
이러한 개념을 렉시컬 스코핑(Lexical Scoping)라 합니다.
function outer() {
let x = 10;
let inner = function() {
console.log(x);
};
return inner;
};
outer(); // 10
위 예제에서 함수 inner는 자신을 포함하고 있는 외부함수(outer)보다 더 오래 남아있습니다. 이 경우 외부함수 밖에서 내부함수를 호출하더라도 외부함수의 지역변수에 접근할 수 있습니다. 이러한 함수를 클로저(Closure)라고 합니다.
클로저는 반환된 내부함수가 자신이 선언되었을 때의 환경인 스코프를 기억하여, 자신이 선언된 환경 외부에서 호출되어도 그 환경에 접근할 수 있는 함수입니다. 즉, 자신이 생성될 때의 환경(Lexical environment)를 기억하는 함수입니다.
2. 클로저(Closure)의 활용
2. 1. 환경의 기억와 유지
클로저는 현재 환경을 기억합니다. 그리고, 환경이 변화할 때마다 가장 최근에 바뀐 상태로 유지합니다.
let funcOnce = function(func) {
let isExcuted = false;
let result;
return function() {
if ( !isExcuted ) {
isExcuted = true;
result = func.apply(null, arguments);
return result;
}
else {
return result;
};
};
};
const add = funcOnce(function(x, y, z) {
return x + y + z;
});
const multiply = funcOnce(function(x, y, z) {
return x * y * z;
});
add(1, 2, 3) // 6
multiply(2, 2, 2) // 8
add(3, 3, 3) // 6
mutiply(1, 1, 1) // 8
-
funcOnce는 Callback 함수를 한 번만 호출하는 함수이고, 이 함수가 반환한 함수는 자신이 만들어진 환경(Lexical Environment)를 기억하는 클로저입니다. 클로저는 변수 isExcuted와 result가 무엇인지 기억합니다.
-
add는 수를 더하는 함수입니다. 이 함수의 결과를 보면, 첫 실행 이후 다음 실행에는 반환값이 전달인자의 합이 아닌 것을 볼 수 있습니다. 변수 isExcuted와 result가 클로저에 의해 참조되므로 유효한 상태이며, 최신상태를 계속 유지하기 때문입니다. 다음 실행(add(3,3,3))에서 isExcuted = true, result = func.apply(null, [1, 2, 3])로 저장되어 있으므로 결과값은 6이 됩니다.
-
변수 add와 multiply는 독립된 환경을 가지고 있습니다. 이는 multiply를 처음 실행했을 때 확인할 수 있습니다. add와 multiply 모두 isExcuted와 result를 가지고 있지만, 독립적으로 실행됩니다. funcOnce를 호출하여 반환된 함수는 자신만의 독립된 환경을 가집니다. 변수 add와 multiply에 할당된 함수는 각각 자신만의 독립된 환경을 가지므로, 자유변수 isExcuted와 result를 공유하지 않습니다. 함수형 프로그래밍에서는 이러한 특징을 이용하여 함수를 재사용하는데, 이를 커링(Currying)라 합니다.
2.2 전역변수 사용 억제
위 스크립트를 실행하면 변수 add와 multiply에는 함수(function() {….})가 할당됩니다. 위에 언급했듯이, 이 함수는 자신이 생성된 환경(Lexical Environment)를 기억하는 클로저입니다. 커링 함수에서 funcOnce는 호출 직후 소멸되지만, 반환한 함수는 변수(add, multiply)에 할당되어, 커링함수를 호출할 때마다 내부에서 호출됩니다.
add, multiply에서 funcOnce는 각각 한 번만 실행되므로, 변수 isExcuted와 result를 다시 초기화하지 않습니다. 또한, 외부에서 직접 접근할 수 없는 지역변수이므로, 전역변수를 사용했을 때와 같이 의도치 않은 변경이 일어나지 않습니다. 전역변수를 만들지 않더라도 초기화되지 않으며 현재 상황을 계속 확인할 수 있는 자유변수를 만들 수 있습니다. 그리고, 자유변수는 전역 스코프에서 직접 접근할 수도 없습니다.
3. Reference
*https://poiemaweb.com/js-closure
*https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Closures
Leave a comment