Javascript Closure
클로져를 알기위해서는 실행 컨텍스트에 대해 알아야 한다.
https://muyeon95.tistory.com/317
클로져는 무엇이고 어떻게 활용할 수 있을까?
정의
MDN : 함수와 함수가 선언된 어휘적 환경의 조합
????????????
확실히 MDN 이 만능은 아니다.
코어 자바스크립트 : 어떤 함수 A 에서 선언한 변수 a 를 참조하는 내부 함수 B를 외부로 전달할 경우 A 의 실행 컨텍스트가 종료된 이후에도 변수 a 가 사라지지 않는 현상
ex code
1)
function something() {
const x = 10;
function sum(y) {
return x + y; // something 함수에서 선언한 x 변수 참조
}
return sum; // 내부함수 sum 을 외부로 전달
}
const some = something();
console.log(some(3)); // 13
// x 변수가 사라지지 않는다.
2)
function sum(x) {
return function (y) {
return x + y;
}
}
const add = sum(2);
console.log(add(7));
1. 코드 평가
- 첫번째로 Global 에 LexicalEnvironment 를 생성하고 전역 코드 평가가 이루어 진다.
- 코드 평가에서는 sum 함수와 add 변수를 호이스팅해 record 에 add 와 sum 함수를 기록해둔다.
- 현재 전역 코드 평가가 이루어지고 있기 때문에 outer 에는 null 이 할당된다.
- 콜 스택에 Global 의 LexicalEnvironment 를 push 하게 된다.
- 코드 평가 과정 종료
2. 코드 순차적으로 진행
- add 변수에 값을 할당하기 위해 sum 함수를 호출한다.
- Global 의 LexicalEnvironment 코드 평가 과정과 동일하게 sum 함수도 LexicalEnvironment 를 생성
- sum 함수 내부의 코드 평가 진행
- 코드 평가에서는 매개변수 x 와 return 문에 있는 익명함수를 호이스팅해 record 에 기록해둔다.
- outer 에는 상위 스코프인 Global 의 LexicalEnvironment 를 가리킨다.
- 콜 스택에 sum 의 LexicalEnvironment 를 push 하게 된다.
- sum의 LexicalEnvironment 의 outer 는 함수가 호출되어 평ㅇ가되는 시점이 아닌 함수가 선언되는 시점에 결정된다.
- Global 의 LexicalEnvironment 코드 평가 과정에 sum 함수가 선언되었으니 sum 의 LexicalEnvironment outer 에는 Global 의 LexicalEnvironment 를 가리키게 된다.
- sum 의 코드 평가 과정이 종료되어 코드가 한 줄씩 실행된다.
- 매개변수 x 에는 인자로 넘겨준 2를 할당
- record 안에 x 변수에 2를 기록
- 이후 실행할 코드가 없으니 sum 의 LexicalEnvironment 는 콜 스택에서 pop 된다.
- Global 의 LexicalEnvironment 로 돌아와 add 변수에 sum 함수의 리턴값인 익명함수를 할당한다.
- record 에 있는 add 변수에 익명함수를 할당한다.
- 마지막 전역 코드인 console.log 를 실행하기 위해 add 함수를 호출하게 된다.
3. add 함수 호출
- add 함수에 호출이 일어나면 add 에 LexicalEnvironment 를 생성
- add 함수 내부 코드 평가
- 매개변수 y 를 호이스팅해 record 에 기록
- outer 에는 sum 의 LexicalEnvironment 를 가리키게 한다.
여기서 이상한 점은 현재 콜 스택에는 Global 의 LexicalEnvironment 만 존재한다.
어떻게 add 의 LexicalEnvironment 의 outer 는 sum 의 LexicalEnvironment 를 가리키게 할 수 있을까?
이런 특성 때문에 클러져라는 현상이 일어난다.
활용
1) before
let cnt = 0;
function cntPlus() {
cnt = cnt + 1;
}
console.log(cnt);
cntPlus();
console.log(cnt);
// 1억개의 코드
cnt = 100;
// 1억개의 코드
cntPlus();
console.log(cnt);
전역으로 선언했을 때 위와같은 문제가 발생한다.
이를 해결하기 위해서 cnt 를 은닉화해 접근을 막고 cnt 의 state 를 유지할 수 있다.
2) after
function closure() {
let cnt = 0;
function cntPlus() {
cnt = cnt + 1;
}
function setCnt(value) {
cnt = value;
}
function printCnt() {
console.log(cnt);
}
return {
cntPlus,
setCnt,
printCnt,
}
}
const cntClosure = closure();
console.log(cntClosure);
cntClosure.printCnt();
cntClosure.cntPlus();
cntClosure.printCnt();
cntClosure.printCnt();
cntClosure.setCnt(100);
cntClosure.printCnt();
참고 링크
https://poiemaweb.com/js-closure
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
https://ko.javascript.info/closure
https://www.youtube.com/watch?v=LL0DGc5pg7A
https://www.youtube.com/watch?v=PJjPVfQO61o