관리 메뉴

Jerry

클로저(CLOSURE)란?? 본문

Front/JavaScript

클로저(CLOSURE)란??

juicyjerry 2021. 4. 22. 13:42
반응형
참고로, 이 글은 인프런, Javascript 핵심 개념 알아보기 - JS Flow, 정재남 강의를 보고서 정리한 내용입니다.

 

오늘 클로저에 대해서 알아보자!

오늘도 클로저를 정복하러 가보자!

💪😎💪😎💪😎💪😎💪😎💪😎💪😎

 

출처: pixabay.com/images/id -60527/

 


 

CLOUSURE의 단어 의미: 닫힘 / 폐쇄 / 완결성 

단어의 의미만 보고 이게 무엇인지 유츄하기 어렵다!

 

MDN에서는

A closure is the combination of a function and the lexical environment within which that function was declared.

함수 X 그 함수가 선언될 당시 X 두 개가 만났을 때 새로운 현상 이 나타나는 것!?

= 실행 콘텍스트 A의 내부에서 함수 B가 콤비가 되어 무언가를 한다!!

 

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).  In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.

(참고로, 현재 MDN에서 정의는 위 문장과 동일하진 않다. 하지만, 의미는 비슷하다고 보인다.)

 

앞선 글에서 이야기 했듯이 (Execution Context, this, callback function)

Lexical Environment 에는 

- environmentRecord와 outerEnvironmentReference가 있는데

그중에 후자가 (외부 함수)A와 (내부 함수)B의 사이에 관계에 관여하는 한다고 볼 수 있다.

 

정리하면, B의 outerEnvironmentReference는 A의 environmentRecord를 참조하며 콘텍스트 A에서 선언한 변수를 내부 함수 B에서 접근할 경우에만 발생하는 특수한 현상

 

필자는 외부에서 내부로 접근 할 때 발생하는 현상이라고 일단 이해를 하고 넘어갔다!

 

 

 

그럼 그 특수한 현상이 뭔데?

먼저, 아래 왼쪽 코드의 실행 콘텍스트는 아래 오른쪽 콜스택처럼 실행되고 종료되면 마지막에 들어온 순서부터 사라지게 된다.

(참고로, LexicalEnvironment만 편의상 표기한 것이다)

 

 

 

그렇다면, 아래 코드의 실행 콘텍스트는 어떻게 될지 생각해보자!

 

 

먼저, 전역 콘텍스트의 environmentRecord는 outer와 outer2라는 변수를 수집했다.

현재까지 outer 변수에 대한 함수가 담겨 있지만 outer2는 실행이 시작할 때까지 담겨있지 않는 걸 볼 수 있다.

 

 

이 상태에서 실행하게 되면, outer에 대한 실행 콘텍스트가 열리면서 environmentRecord에는 a에 1이 들어가고 inner가 들어간다.

outer가 실행이 끝나고 inner가 반환된다.  반환된 inner는 변수 outer2에 담기게 된다.  

 

 

 

빗금 표시를 한 이유는 outer2에서 inner를 언젠가 호출하는 걸 알고 있으니 outer를 마냥 kill 할 수 없다.

outer2에 inner 함수가 담겨있으며 inner 함수 내부에서 a를 참조하고 있어 아직 참조 카운트가 유효한 상황이다.

 즉, 콘텍스트는 종료가 됐지만 밖으로 보낸진 inner라는 함수가 내부에서 참조하고 있으니 죽이지 못하고 살아있는 상태이다. 

 

 

그 후, outer2가 실행이 되면서, inner 함수가 실행이 된다. inner 콘텍스트에 의해서 a에 접근하게 되는데 environment 자체에 없고 outerEnvironmentReference에 (참조하는) a가 1이 증가하게 된다.

 

 

그리고, 실행이 종료가 되면서 console.log가 실행된다. (2가 출력된다) 
그다음 outer2도 실행이 되면서 다시 inner 콘텍스트가 실행되고 결국에 console.log에 3이 찍히게 된다. 

 

 

콘솔에 찍히는 a는 전역 콘텍스트가 종료되기 전까지 참조된 상태로 여전히 살아있게 된다. (=참조 카운트가 줄어들지 않는다) 

(만약, 참조 카운트를 줄이려면 outer2 변수에 다른 것을 대입해야 한다. inner에 담겨있는 결과를 지우고 다른 걸 넣어야지 그제야 참조 카운트가 없어지면서 조치를 당할 수 있는 환경이 될 수 있다.)

 

 

특수한 현상이 "이 a는 전역 콘텍스트가 종료되기 전까지 참조된 상태로 여전히 살아있게 된다. (=참조 카운트가 줄어들지 않는다) "라는 것이라고 이야기할 수 있다. (이게 클로저다!!)

 

정리하면, 콘텍스트 A에서 선언한 변수 a를 참조하는 내부 함수 B를 A의 외부로 전달할 경우, A가 종료된 이후에도 a가 사라지지 않는 현상.

 

이런 클로저로 인하여, 지역변수가 함수 종료 후에도 사라지지 않게 할 수 있게 된다.

함수 종료 후에도 사라지지 않는 지역변수를 만들 수 있다! (클로저가 가지는 가장 큰 장점이 될 수 있다고 한다!) 

 

함수 종료 후에도 사라지지 않는 지역변수를 만들 수 있는 장점으로

초기화하기에 좋다!

웹앱을 초기화할 때, 어떤 걸 불러오고, 세팅하고... 복잡한게 많지만,

처음부터 끝까지 들고 있을 필요는 없고 들고 있어야 할 것은 몇 개 없는 경우에

초기화 셋팅 용도로 클로저로 만들고 계속 들고 있어야할 애들만 리턴 시키면

나머지 애들은 함수가 종료되는 순간에 없어지게 되겠지만 남겨져야 할 애들은 남겨져 사용할 수 있을 것이다. 

 

클로저를 활용해, 초기화시 선택적으로 원하는 값을 임의로 내부로 꺼낼 수 있다는 클로저의 장점!

 

다음, 예시 코드를 보자!

이번에는 getter, setter를 묶은 객체 전체를 리턴해본다.

 

 

  • obj.a를 실행하게 되면 getter에 의해서 localA가 리턴한다.
  • obj.a = 3을 하게 되면 setter에 의해 localA가 3이 된다. 
  • obj라는 외부 변수는 객체인데, 객체 안에서 getter, setter를 이용해 a라는 프로퍼티를 접근해 a라는 값을 바꿀 수도 있고 읽어올 수 있다. 그렇지만, localA에 대해서 직접 접근할 수 없다. 지역 변수를 보호하면서도 접근할 수 있는 수단을 외부에서 해준 것이다. 
  • obj.b에 접근해봤자 내부에 있는 값과 다른 값을 반환하고 b라는 값을 바꾸려고 하면 에러를 던진다. (클로저에 의한 안전장치)
  • localA, B, C는 외부에서 값을 읽어올 수 있게, 변경할 수 있게 할 수 있지만, 값을 읽지 못하게 할 수 있고, 변경 못하게 할 수 있고, 아예 엉뚱한 값을 뱉어낼 수도 있다.

 

즉, 전적으로 클로저를 만든 함수의 마음대로 원하는 결과를 지정할 수 있다.

혹은 클로저에서 부여한 내부에서 준 권한만 사용할 수 있다. 요구할 수 있다.

(객체지향 측면에서 볼 때, 함수에게 인격을 부여하여 인격이 있는 존재라고 생각했을 때, 함수의 마음대로 의지를 담을 수 있다) 

 

외부에 무엇을 보여줄지? 남이 요구할 때, 내가 어떤 방식으로 어떤 값을 보여줄지 말지, 남의 요구에 대해 어떤 태도로 대할지 전적으로 클로저에 마음에 따라 달라진다.

 

다시 말하지만, 함수 종료 후에도 사라지지 않는 지역변수를 만들 수 있다!

 

결국, 클로저란 클로저란 외부 함수의 변수를 참조하는 내부 함수가 외부로 전달될 경우 외부 함수가 종료된 이후에도 참조한 변수가 사라지지 않는 현상입니다! 이라고 기억해보자!

 

 

 

추가로 읽어보면 좋은 레퍼런스

https://meetup.toast.com/posts/86

developer.mozilla.org/ko/docs/Web/JavaScript/Closures

poiemaweb.com/js-closure

반응형