2 분 소요

클로저

  • 클로저는 함수와 외부변수와의 관계이다.
  • 클로저가 어려운게 클로저가 문제가 아니라 for문(반복문)과 비동기를 함께 사용하면 종종 발생한다.
  • 해결방법으로는 2가지가 있다.
    • var 유지 => 즉시 실행함수로 클로저 생성 <== 이게 클로저를 활용해서 해결한 방법이다.
    • var => let 클로저를 활용하지않고 varlet으로 바꿔주어서 해결할 수 있다.
function a() {
	for (var i = 0; i < 5; i++) {// 여기서 var 는 a()로 올라간다. i가 4일 때까지는 true인데, i가 5가 되고, 5 < 5가 false 
        setTimeout(() => {   
            console.log(i);
		}, i * 1000);
	}
}
a();
//5
//5
//5
//5
//5

우리는 원하는건 1초뒤에 0, 2초뒤에 1, 3초뒤에 2, 4초뒤에 3, 5초뒤에 4를 출력하고 싶은데 위에 코드를 돌려보면 1초, 2초, 3초, 4초, 5초뒤에도 모두 5가 출력된다.

그 이유는 위 코드에서 varfunction a 스코프는 한개고, 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);  // 이렇게 하면 f(j)가 5번 반복되기 때문에 
			}, i* 1000);
		})(i);
	}
}
a();
//0
//1
//2
//3
//4
  • var => let 으로 바꿔주어서 해결하면
function a() {
	for (let i = 0; i < 5; i++) {
	setTimeout(() => {
		console.log(i);
		}, i * 1000);
	}
}
a();
//0
//1
//2
//3
//4

만약 cnt 라는 값은 무조건 cntPlus으로만 바꾸고 싶은 경우를 구현해 보고 싶다고 한다면

무조건 이 함수가 실행 됐을 때만 1씩 증가시키도록 코드를 구현하는거다.

그런 코드를 짜고 싶으면 이런 식으로 짤 수 있을 것이다.

let cnt = 0;
function cntPlus() {
    cnt = cnt + 1;
}
console.log(cnt); // 0
cntPlus();
console.log(cnt); // 1


// 만약에 
// 1억개의 코드
cnt = 100;
//  1억개의 코드 
cntPlus();
console.log(cnt); // 101

내가 가정한 상황은 이 cnt 라는 변수는 무조건 cntPlus 로만 값을 증가 시킬 수 있고 다른 걸로 바꾸면 안되는 그런 상황인데 이 중간에 cnt라는 변수가 접근 가능하기 때문에 내가 생각하는 상황을 완벽하게 구현 할 수 없다.

이런 상황을 해결하려면 변수를 접근 못 하게 해야한다.

이때 필요한게 “클로저” 이다.

일단 cnt가 전역변수이기 때문에 cnt를 지역변수로 바꿔 줘야 한다. 즉, 함수로 감싸준다.

이렇게 하면 밖에서 참조를 할 수 없게되지만 cntPlus를 실행시킬수 없다. 이때 cntPlus를 사용하려면 return을 사용해야한다. 이렇게 하면 cntPlus를 실행시킬 수 있지만 cnt자체를 출력시키고싶으면 어떻게 해야 할까?

function closure() {
 let cnt = 0;
 function cntPlus() {
     cnt = cnt + 1;
 }
    return {
        cntPlus,
    }
}

const cntClosure = closure();
console.log(cntClosure); // { cntPlus: [Function: cntPlus] }
cntClosure.cntPlus();

이럴 땐 출력하는 함수 printCnt를 만들면 된다. 이렇게 cnt라는 값은 기타 다른 방법으로는 이 값을 절대 바꿀 수 없다. 이 변수에 접근하는 방법은 오직 cntPlus() , printCnt() 말고는 없다. 이렇게 하면 위에서의 기능을 구현할 수 있다. 추가적인 기능이 필요 할때는 함수를 return하는 방식으로 구현한다.

function closure() {
 let cnt = 0;
 function cntPlus() {
     cnt = cnt + 1;
 }
    function printCnt() {
        console.log(cnt);
    }
    return {
        cntPlus,
        printCnt,
    }
}

const cntClosure = closure();
console.log(cntClosure); // { cntPlus: [Function: cntPlus] }
cntClosure.printCnt(); // 0
cntClosure.cntPlus();
cntClosure.printCnt(); // 1

참고: 제로초 강의

댓글남기기