Jiho1996 2022. 8. 6. 16:45

자유변수 참조하는 함수를 리턴하는 함수를 클로저(closure)라고 한다.

이 자유변수를 참조하는 함수는 선언 될 때 환경을 [[Environment]] 프로퍼티에 저장한다.

 

그렇다면 closure의 목적은 무엇일까?

자바 등의 다른 객체 지향언어를 써보면 클래스를 활용하며 private protected public등의 지정자를 만난 적이 있을 것이다

(자바스크립트는 클래스를 지원하긴 하나 정확히는 prototype을 활용해 객체지향을 준수한다.)

하나의 변수에 이곳 저곳에서 참조를 하여 쓰고 값의 변경을 준다면 이는 큰 문제가 될 소지가 있다.

그렇기에 closure는 변수를 숨기기에 목적이 있다.

예시를 들어본다.

function Character(name){
	this._name = name;
}

Character.prototype.useSkill = function () {
	console.log(`${this._name}의 호흡 벽.력.일.섬`);
}

let jiho = new Character("지호");
jiho.useSkill(); // 지호의 호흡 벽.력.일.섬

jiho._name = "진호";
jiho.useSkill(); // 진호의 호흡 벽.력.일.섬

여기서 ._이란 private을 의미한다.

지호의 스킬이 순식간에 진호에게 빼앗겼다.

이렇게 외부에서 접근할 수 없는 값을 만들기 위해 클로저가 필요하다.

 

해결책

function Character(name){
	let _name = name;
    return function (){
    console.log(`${_name}의 호흡 벽.력.일.섬`);
   }
}

let jiho = Character("지호");
jiho(); // 지호의 호흡 벽.력.일.섬

jiho._name = "진호";
jiho(); // 지호의 호흡 벽.력.일.섬

 

._name이 private값으로 변경되어 ._name값으로 접근불가한 것을 확인.

 

 

이제 이해가 안갔던 보통 서적들에서 있는 책들  예시를 보자.

 

var i;
for (i=0;i<10;i++){
	setTimeout(function(){
    	console.log(i);
       }, 100)
   }

이는 

1. 먼저 i가 선언

2. for문으로 i=0됨.

3. 허나 settimeout을 만나고 뒤에 콜백함수는 web api에 들어가게 됨. 그리고 0 루프 종료 (동기)

4. 이렇게 0 -> 9까지 끝남

5. 0->9까지 도는 동안 settimeout의 1초가 지나서 매크로 큐에 쌓이고 콜스택이 비워지길 기다림.

6. anonymous 즉 동기 함수가 모두 끝나면 차곡 차곡 다시 콜스택으로 올라가는데 이때 i는 이미 10인 상태.

 

즉 10이 10번찍힌다.

 

해결책

 

즉시 실행 함수.

 

(function(v){
	console.log(v);
})(10); // 10

v를 파라미터로 받고 즉시 실행을 위해 10을 넣었으니 인자로 10을 받는 셈이 된다.

 

var i;
for (i=0;i<10;i++){
	(function(j){
	setTimeout(function(){
    	console.log(j);
       }, 100)
   })(i)}

1. for문 안에 IIFE실행.

2. i값이 반복되고 이 반복 되는 i값은 j에 할당.

3. settimeout안의 콜백함수는 이를 참조. 이때 prototype내의 [[Environment]]에 이 j값이 저장.

4. 그 동안 settimeout안 콜백함수는 web api가서 0.1초 기다린다.

5. 전부 다 기다렸다면 매크로 태스크 큐에 들어간다.

6. 모든 콜스택이 종료되었다면 마찬가지로 실행.

7. 헌데, 실행하면서 참조하는 j는 environment에 저장한 렉시컬 스코프 변수 j를 불러와서 찍는다.

8. 0 1 2 3 4 5 6 7 8 9 가 찍힘.

 

클로저 사용시 단점.

prive value에 찾아 들어가기에 추가 시간 및 private value 참조하는 약간의 메모리가 듦. 하지만 크진 않다고 한다..