JS/인간 JS엔진
클로저
5_hyun
2024. 1. 30. 00:03
반응형
클로저
클로저란?
- 함수와 외부 변수와의 관계
- 클로저란 내부 함수가 외부로 반환된 이후에도 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
반응형