일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 타입스크립트
- 파이썬 for in
- JavaScript
- 타입스크립트 props
- 내일배움캠프
- 내일배움캠프 최종 프로젝트
- 파이썬 for
- 코딩테스트
- 한글 공부 사이트
- 리액트
- REACT
- 자바스크립트
- 파이썬 enumerate
- 리액트 공식문서
- 리액트 훅
- useEffect
- 파이썬 slice
- 리액트 프로젝트
- 프로그래머스
- 파이썬 replace
- 내배캠 프로젝트
- React Hooks
- 파이썬 딕셔너리
- 타입스크립트 리액트
- Next 팀 프로젝트
- useState
- 내일배움캠프 프로젝트
- tanstack query
- 파이썬 반복문
- typeScript
- Today
- Total
sohyeon kim
[JS] Closure 클로저, Lexical Environment 렉시컬 환경 본문
💡 렉시컬 환경 : 어떤 함수가 선언(생성)될 때 그 당시의 외부 변수가 저장되는 곳!
그 정보들 : 외부 변수 등등
const x = 1; // 전역 스코프
function outerFunc() {
const x = 10; // outerFunc 스코프
function innerFunc() {
console.log("x : " + x); // x : 10
// (innerFunc 스코프에 x 가 없으니 이 함수가 선언될 때의 LE 인 outerFunc 로 찾으러 감)
}
innerFunc();
}
outerFunc();
console.log("x : " + x); // x : 1
➕ 함수를 어디서 '호출' 했는지가 아니라,
어디에 '정의' 했는지에 따라 스코프(상위 스코프) 가 결정된다!
outer 내에 inner 가 '호출' 되고 있음에도 불구하고
outer 와 inner 는 서로 다른 scope 를 가지고 있다.
const y = 1;
function outerFunc2() {
const y = 10;
innerFunc2(); // inner 함수가 여기서 불려서 y = 10 일 것 같지만
}
// 사실 여기에 위치한 것이라 전역 스코프를 바라본다.
function innerFunc2() {
console.log("y : " + y); // y : 1
}
outerFunc2();
💡 클로저 : 외부 함수보다 중첩 함수가 더 오래 유지되는 경우,
중첩 함수는 이미 생명 주기가 종료된 외부 함수의 변수를 여전히 참조할 수 있다.
그 중첨 합수가 바로 클로저!
const z = 1;
function outerFunc3() {
const z = 10;
const inner = function () {
console.log("z : " + z); // z : 10 ** 3 **
};
return inner;
}
const innerFunc3 = outerFunc3(); // ** 1 **
// outerFunc3 를 실행해 innerFunc3 에 담음
// = outerFunc3 의 return 부분을 innerFunc3 에 담는다는 얘기!
// = inner
// = function () {
// console.log("z : " + z); // z : 10
// };
innerFunc3(); // ** 2 **
실행 컨텍스트를 상상해 보자 ~
** 1 ** 에서 outer 가 실행이 되고 없어졌으니 z 가 1이 나올 것 같지만
나중에 inner 에서 사용될 outer 의 변수가 사라지지 않고 유지되어서 값으로 10 이 나온다!
❗️ outer 함수의 LE 를 참조하는 곳(innerFunc3) 이 있으니까 가비지 컬렉터가 냅두는 것!
💡 클로저와 클로저가 아닌 것을 구분해 보자 ~
function foo() {
const k = 1;
// bar 함수는 클로저였지만 곧바로 소멸한다.
// 외부로 나가 따로 호출되는게 아니라, 선언 후 바로 실행 + 소멸
// 이런 함수는 일반적으로 클로저라고 하지 않는다!
function bar() {
console.log("k : " + k); // k : 1
}
bar();
}
foo();
function foo2() {
const k2 = 3;
// 클로저의 예
// 중첩 함수 bar2 는 외부 함수 foo2 보다 더 오래 유지되며
// 상위 스코프 foo2 스코프의 식별자 k2 를 참조한다.
function bar2() {
console.log("k2 : " + k2); // k2 : 3
}
return bar2;
}
const bar2 = foo2();
bar2();
💡 클로저는 주로 "상태를 안전하게 변경하고 유지하기 위해 사용한다!"
상태를 안전하게 은닉한다(특정 함수에게만 상태 변경을 허용한다.) 는 표현을 기억하자.
// 함수가 호출될 때마다 호출된 횟수를 누적하여 출력하는 카운터를 구현할래!
let num = 0;
const increase = function () {
return ++num;
};
console.log(increase()); // 1
num = 100; // 누가 num 을 바꿔버림
console.log(increase()); // 101 => 원치 않던 값 출력
console.log(increase()); // 102 => 원치 않던 값 출력
보완해야 할 사항
1. 카운트 상태(num 변수의 값) ➡️ increase 함수가 호출되기 전까지는 변경되지 ❌
2. 이를 위해 count 상태는 increase 함수만이 변경!
3. 전역변수 num 이 문제다! ➡️ 그럼 지역변수로 바꿔볼까..?
const increase = function () {
let num = 0;
return ++num;
};
console.log(increase()); // 1
console.log(increase()); // 1
console.log(increase()); // 1
지역변수로 넣어서 변경은 방지했지만! (현재 num 변수는 오직 increase 함수만이 변경할 수 있음)
호출될 때마다 num 이 0 으로 초기화된다. 😶
여기서 클로저를 써보자!!
const increase = (function () {
let num = 0;
// 클로저
return function () {
return ++num;
};
})();
console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3
increase 는 function () { return ++num; } 을 뱉어낸다! = 할당된다!
저 뱉어낸 값은 외부함수(num) 를 참조하고 있으니 num 은 가비지 컬렉터가 가져가지 않고 유지된다.
정리하면..
1. 위 코드가 실행되면, '즉시 실행 함수'(function () { let num ~~ ++num; } ; }) 가 호출된다.
➡️ 함수가 반환(그 안에 있는 함수) ➡️ increase 에 할당
2. increase 변수에 할당된 함수는 자신이 정의된 위치에 의해
결정된 상위 스코프린 즉시 실행 함수의 LE 를 기억하는 클로저! ➡️ let num = 0; 을 기억한다.
3. 즉시 실행 함수는 즉시 소멸된다! (outer 함수가 불리자마자 바로 call stack 에서 pop up 되는 것과 비슷..!)
결론 : num 은 초기화 ❌ 외부에서 접근할 수 없는 은닉된 값이 되었다!
의도되지 않은 변경도 걱정할 필요가 없다! increase 에서만 변경할 수 있기 때문에!
'JavaScript' 카테고리의 다른 글
[JS] array 배열 메소드 활용 : filter, reduce, find (0) | 2024.01.17 |
---|---|
[JS] null 병합 연산자 '??' (0) | 2024.01.08 |
[JS] class 클래스 사용법, get & set, Static 정적 메소드 (1) | 2024.01.04 |
[JS] Map 맵 : new Map(), map.set(), map.get() (1) | 2024.01.02 |
[JS] First Class Object 일급 객체 함수, 고차함수 ,함수 활용 (0) | 2024.01.02 |