클로저는 JavaScript ES6 이전 버전부터 존재한 개념으로, 다음과 같이 설명할 수 있다.
-> 어떤 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상
하지만, ES6에 도입된 let과 const는 함수 스코프 뿐만 아니라, 블록 스코프를 가지기 때문에 다음과 같이 수정할 수 있을 것 같다.
-> 어떤 블록에서 let 또는 const를 선언한 변수 a를 참조하는 함수 B를 블록 외부로 전달할 경우, 블록의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상
var와 let, const의 차이
https://velog.io/@juwon98/var-vs-let-const
클로저(Closure)
https://velog.io/@juwon98/JavaScript-Closure
클로저에서 var와 let, const의 동작에 어떤 차이가 있는지 자세히 알아보자.
let funcs = [];
for(var i=0; i<3; i++) {
funcs[i] = function(){
console.log(i);
}
}
funcs[0](); // 3
funcs[1](); // 3
funcs[2](); // 3
각각의 함수가 0, 1, 2를 출력할 것으로 예상하는 것이 일반적이지만, 의도와 달리 var의 경우는 블록스코프를 가지지 않는 i 변수가 사라지지 않아 접근 가능한 i를 참조하게 되어 모두 3을 출력한다.
이 경우에는 클로저가 발생하지 않는다.
let funcs = [];
for(let i=0; i<3; i++) {
funcs[i] = function(){
console.log(i);
}
}
funcs[0](); // 0
funcs[1](); // 1
funcs[2](); // 2
let을 사용하여 선언한 변수i는 for문의 각각의 블록(3회 반복이므로 3개의 블록이 존재)마다 생성되고 사라지기 때문에 for문의 블록이 종료된 후에는 접근하지 못하는 것이 일반적이다. 하지만, funcs[0], funcs[1], funcs[2]는 모두 이미 종료된 블록에 존재하는 i(이름은 같지만 각각 다른 3개의 변수 i이다)를 참조하고 있어, 변수 i가 가비지 콜렉터의 수집대상이 되지 않아 메모리에 존재하기 때문에 접근가능한 클로저가 발생하고 있다.
일반적인 예상대로 0, 1, 2가 출력되어 의도에 맞게 코드를 작성할 수 있지만, 생각보다 복잡한 클로저의 개념이 적용되고 있는 것을 알 수 있다.