6. 클로저

gugyeoj1n·2022년 4월 26일
0

자바스크립트

목록 보기
6/9

오늘 원래 저녁 출이었는데 밤 10시 반에 나간댄다. 미치겠다
키보드 배송만을 기다리면서 오늘도 공부를 하겠다. 얼른 와 주세요 ~.~

클로저 Closure

클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. 클로저를 이해하려면 자바스크립트가 어떻게 변수의 유효범위를 지정하는지(Lexical scoping)를 먼저 이해해야 한다.

라고 MDN에 쓰여 있다. 함수가 선언된 어휘적 환경은 LexicalEnvironment 를 가리키고, 즉 클로저는 내부 함수와 LexicalEnvironment 의 조합이라 할 수 있다. 이 클로저는 함수가 생성될 때마다 매번 발생해서 뭔가 특수하다기보단 당연한 개념이다. 클로저 환경에서만 발생하는 어떤 특별한 현상이 존재하기 때문에 클로저를 언급하는 것이다.

콜스택에 A 실행 컨텍스트, B 실행 컨텍스트가 차례대로 담겨 있다고 가정해 보자. B의 outerEnvironmentReference 로 A의 environmentRecord 에 접근할 수 있다. 이 외에 두 실행 컨텍스트가 서로 관여할 수 있는 부분은 없고, 둘 사이의 조합은 이 1개뿐이다. 여기서 발생할 수 있는 현상은 A 실행 컨텍스트에서 선언한 변수를 B 실행 컨텍스트 속 함수가 참조할 때 생기는 현상이 해당된다.

var outer = function () {
	var a = 1;
  	var inner = function () {
    	console.log(++a);
    };
  	inner();
}

outer();

코드 언어 설정해 주면 이렇게 이쁘장하게 색칠해 준다. 몰랐다.

아무튼 outer 함수를 하나 만들었다. 이 자체로 전역 컨텍스트와 outer 내부에서 선언한 변수 사이에 클로저가 생성되었다. 하지만 전역 컨텍스트에 선언해 둔 변수를 outer 가 참조하는 상황이 아니니 뭔가 특별한 일은 일어나지 않았다. 이제 outer 함수 안을 보면, 변수 a가 있고 a의 값을 바꾸는 inner 함수가 있다. outer 실행 컨텍스트에서 선언된 변수 (a) 를 내부 함수 inner 가 참조하고 있다. 근데 이게 왜 특별한 현상이 될까?

var outer = function () {
	var a = 1;
  	var inner = function () {
    	return ++a;
    };
  	return inner;
}

var outer2 = outer();
console.log(outer2());
console.log(outer2());

기능은 같지만 구조가 좀 다른 코드를 가져왔다. 9번째 라인에서 outer 실행 컨텍스트가 콜스택에 들어오고 내용을 실행한다. inner 를 반환하니 outer2 에는 inner 가 담기고, outer 실행 컨텍스트가 종료되는 게 정상적인 절차일 것이다. 하지만 outer 실행 컨텍스트는 깔끔하게 사라지지 않는다. inner 를 갖고 있는 outer2 때문에 inner 내부에서 참조하는 a 의 참조 카운트가 0이 아니기 때문이다. 두 번의 console.log 가 실행되고 전역 컨텍스트까지 종료돼야 남아있던 변수 a 까지 사라질 것이다.

처음에 얘기했던 A 실행 컨텍스트에서 선언한 변수를 내부 함수 B가 참조할 때 생기는 현상과 맞아 떨어진다. (B 실행 컨텍스트 속 함수를 편의상 내부 함수 B로 하겠다) 이 내부 함수 B를 A의 외부로 전달할 때, A가 종료되어도 그 변수가 사라지지 않는 이 현상이 클로저의 핵심이다. 구질구질하게 남아있는 별로 좋지 않은 현상같기만 하다. 하지만 지구의 수많은 천재들이 이를 지역변수가 함수 종료 후에도 사라지지 않게 할 수 있다 로 재해석했다. 어쩌면 이 기능을 다들 자연스럽게 써 오고 있었을 것이다.

function user(_name) {
	var _logged = true;
  	return {
    	get name() { return _name },
      	set name(v) { _name = v },
      	login() { _logged = true },
      	logout() { _logged = false },
      	get status() {
        	return _logged ? 'login' : 'logout';
        }
    }
}

var me = user("구겨진");

간단하게 이름, 로그인 여부 정보를 담은 객체를 만들어 주는 함수 user 를 가져왔다.
마지막 줄에서 user 함수가 실행되면서 me 가 만들어지고, user 실행 컨텍스트는 종료된다. 하지만 return 속 함수들이 _name 과 _logged 를 참조하고 있기 때문에 두 변수는 사라지지 않는다. 덕분에 이 뒤에 me 의 name 을 조정하거나 로그인 여부를 확인할 수 있는 것이다.

이런 식으로 클로저에는 함수가 종료되어도 변수를 남겨서 사용할 수 있다는 장점이 있다.





재밌다
빨리 키보드 오면 좋겠다 근데 전역해야 제대로 쓸 수 있음 그니까 전역하고 싶다
시간이 너무 느릿느릿 가 ~...~ 마음도 힘들고 몸도 힘들고

0개의 댓글