일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 |
Tags
- 타입 좁히기
- React
- 투포인터
- 이분 검색
- 결정 알고리즘
- CI/CD
- 공변성
- async/await
- useAppDispatch
- TS
- SSR
- webpack
- CORS
- ESlint
- app router
- recoil
- Jest
- autosize
- tailwind
- 반공변성
- Promise
- Cypress
- 리터럴 타입
- dfs
- 호이스팅
- map
- RTK Query
- 인터섹션
- 무한 스크롤
- 태그된 유니온
Archives
- Today
- Total
짧은코딩
클로저 본문
반응형
클로저
클로저란?
- 함수와 외부 변수와의 관계
- 클로저란 내부 함수가 외부로 반환된 이후에도 life-cycle 이 유지되는 것
- 클로저 안에 정의된 함수는 만들어진 환경을 기억
클로저가 어려운 이유
- 스코프, 비동기, var 등이 모두 섞여있다.
- 클로저가 문제가 아니라, 클로저를 사용해서 해결하는 문제가 대부분이다.
- 주로 for문(반복문)과 비동기를 함께 사용하면 종종 발생
예시
var을 한 경우
function a() {
for (var i = 0; i < 5; i++) { // i가 4일때까지는 true, i가 5가 되고 5 < 5 false
setTimeout(() => {
console.log(i);
}, i * 1000); // 0, 1000, 2000, 3000, 4000
}
}
a();
-결과

-문제점
- var과 for과 비동기가 섞여있다.
- 해결법 1
- var 유지 -> 즉시 실행 함수로 클로저 생성
- 해결법 2
- var -> let으로
-분석

- for에서 var을 사용하면 특이하게 상위 스코프에 변수가 들어가게 된다.
- 따라서 i가 a의 스코프에 있다.
- for 문을 돌면서 i가 증가하고, i가 5가 되면 코드의 실행이 종료된다.
- for 문이 돌면서 setTimeout은 비동기니까 콜백 함수가 백그라운드로 넘어간다.
- 특이하게 setTimeout의 시간 부분은 잘 돌아간다.
- 사진은 함수 a의 동기 부분이 모두 실행되고 난 상태이다.
- 이제 비동기 부분이 실행되는데 i가 5가 되어있어서 출력 결과가 모두 5가 나오게 된다.
- 결론
- function a의 스코프는 1개, for문의 스코프는 5개
- a 스코프에서 i는 0 -> 5가 되는 거고, for문의 스코프 5개에서 i는 각각 0, 1, 2, 3, 4
즉시 실행 함수를 사용하여 해결한 경우(새로운 클로저 관계를 만들어서 해결함)
function a() {
for (var i = 0; i < 5; i++) {
(function (j) {
setTimeout(() => {
console.log(j);
}, i * 1000); // 0, 1000, 2000, 3000, 4000
})(i);
}
}
a();
-결과

-분석

- 이 코드에서는 즉시 실행 함수를 사용하여 해결했다.
- 즉시 실행 함수는 선언이자 호출이다.
- 이 코드에도 for 문은 var이 있어서 일단 상위 스코프인 a에 i가 선언된다.
- for 문 안에 즉시 실행 함수가 있어서 스코프가 나눠지게 된다.
- 그렇기에 j의 값이 다른 함수 스코프가 생긴다.
- 즉시 실행 함수의 i를 j로 고정시켰다.
- setTimeout의 콜백 함수에서는 각각 다른 형제 스코프에 접근하기에 j의 값이 달라지게 할 수 있다.
- 이 그림도 동기 부분까지만 실행한 상태이다.
- 클로저
- 즉시 실행함수와 for문이 클로저 관계이다.
- setTimeout의 콜백 함수와 즉시 실행 함수의 j(외부 변수)가 클로저 관계이다.
let을 사용한 방법
function a() {
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
}, i * 1000);
}
}
a();
-결과

-분석

- for 문에서 let으로 사용하면 i의 선언이 for 문 안에 된다.
- i = 5가 되면 더 이상 코드가 실행되지 않는다.
- 따라서 for문의 형제 스코프들이 같은 i를 사용하기에 결과가 잘 나오는 것을 알 수 있다.
-출처
https://www.youtube.com/watch?v=4hhlfq3Uy6U&list=PLcqDmjxt30Rt9wmSlw1u6sBYr-aZmpNB3&index=18
반응형
'JS > 인간 JS엔진' 카테고리의 다른 글
await 연달아쓰면 Promise.allSettled를 생각해보자 (0) | 2024.01.29 |
---|---|
async/await, Promise로 바꾸기 (1) | 2024.01.28 |
Promise에도 동기는 있다! (0) | 2024.01.27 |
비동기는 동시가 아니다 (2) | 2024.01.27 |
Promise, async/await (2) | 2024.01.25 |