클로저(Closure)
함수 + 함수를 둘러싼 환경(Lexical environment)
함수를 둘러싼 환경이라는 것이 바로 앞에서 설명했던 렉시컬 스코프다.
함수를 만들고 그 함수 내부의 코드가 탐색하는 스코프를 함수 생성 당시의 렉시컬 스코프로 고정하면 바로 클로저가 되는 것
자바스크립트의 클로저
자바스크립트에서 클로저는 함수가 생성되는 시점에 생성된다.
= 함수가 생성될 때 그 함수의 렉시컬 환경을 포섭(closure)하여 실행될 때 이용한다.
어떤 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상을 말한다.
const A = function () {
let a = 1;
const B = function () {
return ++a;
}
return B;
};
const copyA = A();
for (let i = 0; i < 3; i++) {
console.log(copyA()); // 2 3 4
}
a의 값이 계속 남아 2 3 4처럼 하나씩 증가 되는 값을 console log를 통해 확인 할 수 있었다.
예제를 확인해보면 내부함수를 외부로 전달 하였을 때 컨텍스트가 종료 된 이후에도 변수는 사라지지 않는 것을 보여준다. 왜냐하면 copyA가 A함수를 호출하면서 내부함수 B를 참조하게 되었기 때문이다.
GC 특성 상 더이상 사용하지 않는 변수를 수거하지만 copyA가 B를 참조하면서 B내부에 있는 a 변수를 계속해서 참조를 하게 되었다. 그로인해 A함수 실행 완료 후 A함수가 실행컨텍스트에서 제거 되어야하지만 변수 a를 사용한 B 함수에 의해 A 함수의 변수 a는 제거되지 않고 남아있게 된다.
클로저의 개념을 다시 설명하게 되면 내부함수 B가 Lexical Environment(자신이 실행되었을 때의 환경)를 기억하는 함수이다.
사용 예시
클로저의 경우 잘 못 사용할 경우 데이터가GC에 수거 되지 못하고 메모리누수 현상이 일어날 수 있지만. 클로저를 사용하게 되면 가질 수 있는 장점들이 있기 때문에 메모리 누수문제만 해결 할 수 있다면 클로저를 사용하는 것이 좋다.
현재 상태에 대한 정보를 유지해야 하는 경우
(function s(){
let a = 'hi'
})() //a is not defined
이러한 방식과 같이 직접적으로 변경되면 안 되는 변수에 대한 접근을 막는 것을 은닉화라고 한다.
function hello(name) {
let _name = name;
return function () {
console.log('Hello, ' + _name);
};
}
let a = new hello('영서');
let b = new hello('아름');
a() //Hello, 영서
b() //Hello, 아름
이렇게 a와 b라는 클로저를 생성함으로써 함수 내부적으로 접근이 가능하다.
function a(){
let temp = 'a'
return temp;
}
// console.log(temp) error: temp is not defined
const result = a()
console.log(result); //a
위 함수 내부적으로 선언된 temp에는 직접적으로 접근을 할 수 없습니다. 함수 a를 실행시켜 그 값을 result라는 변수에 담아 클로저를 생성함으로써 temp의 값에 접근이 가능합니다.
이렇게 함수 안에 값을 숨기고 싶은 경우 클로저를 활용해볼 수 있습니다.