클로저란 함수와 그 함수가 선언된 렉시컬 환경의 조합이다.
외부 함수가 return을 했기 때문에 콜 스택에서 제거되지만,내부 함수가 참조하고 있기 때문에 렉시컬 환경에는 아직 남아있다. (가바지 컬렉터가 안가져간다.)
마치 스택에서 제거될 때의 상태를 기억하고 사라졌다가, 다시 호출하면 기억한 상태로 복귀하는 느낌이다. 자신이 선언될 당시의 환경을 기억하는 함수라고 보면 될 것 같다.
클로저의 핵심은 스코프를 이용해서, 변수의 접근 범위를 닫는(폐쇄)것에 있다.함수가 호출되는 환경과 별개로, 기존에 선언되어 있던 환경(어휘적 환경)을 기준으로 변수를 조회한다.
클로저는 console.log 같은 실행만 띡 하고 사라지는 함수가 아니면서 상위 스코프(외부 식별자)를 참조해야한다.
외부 식별자를 참조하지만, 호출되어 실행만 하고 소멸된다면 클로저 xreturn값이 되어, 외부 함수보다 더 오래 유지 되어도 상위 스코프(외부 식별자)를 참조하지 않는다면 클로저 x
코어 자바스크립트 저자 왈,클로저는 let 선언을 해라.다 쓰면 의도적으로 없애라.
function createCounter() {
let count = 0;
return function() {
return ++count;
}
}
const counter = createCounter();
console.log(counter()); // 출력: 1
console.log(counter()); // 출력: 2
클로저 내부에서 선언된 변수는 외부에서 접근할 수 없기 때문에, 클로저를 사용하여 정보를 은닉하고 접근을 제어할 수 있다.
for (var i = 1; i <= 5; i++) {
(function(index) {
setTimeout(function() {
console.log(index);
}, 1000 * index);
})(i);
}
function foo() {
const x = 1;
const y = 2;
function bar() {
const z = 3;
console.log(z); // 상위 스코프의 식별자 참조 X, 같은 스코프의 식별자 참조
}
return bar;
}
const bar = foo();
bar();
function foo() {
const x = 1;
function bar() { // 곧바로 소멸
debugger;
console.log(x);
}
bar(); // 얘 때문에 안돼
}
foo();
function foo() {
const x = 1;
const y = 2;
function bar() { // 외부 함수보다 더 오래 유지.
debugger;
console.log(x); // 상위 스코프의 식별자 참조.
}
return bar;
}
const bar = foo();
bar();
function makeAdder(x) {
// 클로저
return function(y) {
return x + y;
}
}
const add5 = makeAdder(5);
console.log(add5(3)); // 출력: 8
위의 코드에서 makeAdder
라는 함수는 인자로 받은 x
값을 기억하고 있는 클로저 함수를 반환한다.반환된 클로저 함수 add5
는 x
값을 기억하고 있어, 나중에 호출될 때에도 x
값을 사용할 수 있다.따라서 add5
함수를 호출할 때에는 5와 인자를 더하여 원하는 결과를 얻게 된다.
클로저는 함수가 생성될 때의 상태를 기억하고 있기 때문에, 함수 내에서는 해당 상태를 사용하거나 변경할 수 있다. 이를 통해 동적인 동작이 필요한 경우에 유용하게 사용될 수 있다. 클로저는 함수형 프로그래밍이나 자바스크립트의 높은 차원의 유연성과 표현력을 지원하는 중요한 개념 중 하나다.