클로저(closure)란?
- 함수와 함수가 선언된 어휘적(코드가 어디서 실행되며 주변에 어떤 코드가 있는지, lexical 환경) 환경의 조합을 말한다. 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다.
- 중첩함수(함수가 함수를 리턴하는 형태)이고 2. 리턴된 함수가 외부함수의 변수를 참조하면 클로저이다.
- 렉시컬 환경 === 렉시컬 스코프
- 함수 outerFunc는 내부함수 innerFunc를 반환하고 생을 마감했다. 즉, 함수 outerFunc는 실행된 이후 콜스택(실행 컨텍스트 스택)에서 제거되었으므로 함수 outerFunc의 변수 x 또한 더이상 유효하지 않게 되어 변수 x에 접근할 수 있는 방법은 달리 없어 보인다. 그러나 위 코드의 실행 결과는 변수 x의 값인 10이다. 이미 life-cycle이 종료되어 실행 컨텍스트 스택에서 제거된 함수 outerFunc의 지역변수 x가 다시 부활이라도 한 듯이 동작하고 있다.
- 아래 예제에서는 실행이 종료된 outer 함수 속 지역변수 x를 참조하고 있는 innerFunc 함수가 클로저가 된다.
const x = 1; function outerFunc() { const x = 10; // 지역변수 x 선언 const innerFunc = function() { // innerFunc함수 정의 console.log(x); } return innerFunc; // innerFunc함수를 그대로 리턴 } // outer의 역할은 여기서 끝 const innerFuce = outerFunc(); innerFunc(); // outerFunc함수 내부에 있는 innerFunc함수를 실행한다.
side effect
- side effect란 전역 변수에 의해 다른 함수 혹은 로직 등에 의해 의도하지 않은 변경을 초래하는 것을 말한다.
-> 클로저를 통해 불필요한 전역 변수 사용을 줄이고, 스코프를 이용해 값을 보다 안전하게 다룰 수 있다.
const makeCounter = () => {
let value = 0;
return {
increase: () => {
value = value + 1
},
decrease: () => {
value = value - 1
},
getValue: () => value
}
}
const counter1 = makeCounter();
counter1.increase(); // 1
counter1.increase(); // 2
counter1.decrease(); // 1
// getValue 메서드는 외부 함수에 선언된 value 값을 리턴하는 함수
counter1.getValue(); // 1
const counter2 = makeCounter();
counter2.decrease(); // -1
counter2.decrease(); // -2
counter2.dencrease(); // -3
// getValue 메서드는 외부 함수에 선언된 value 값을 리턴하는 함수
counter2.getValue(); // -3
let add = function(x) { // x = 1
let sum = function(y) { // y = 6
return x + y;
}
return sum;
}
let foo = add(1); // foo === sum
foo(3); // foo(3) -> add함수 내부에서 sum(3)
let total = foo(6); // 7
var a = 0;
function foo() {
var b = 0;
return function() {
console.log(++a, ++b);
};
}
var f1 = foo();
var f2 = foo();
f1(); // --> A : 1 1
f1(); // --> B : 2 2
f2(); // --> C : 3 1
f2(); // --> D : 4 2
// 보기
// A. 1 1
// B. 2 2
// C. 1 1
// D. 4 2