close to closure - 1

Sally·2022년 4월 3일
1

우아한 테크코스에서 주어지는 LMS의 학습 키워드에 클로저가 포함이 되어있다.

사실 클로저에 대해서는 이번 우아한 테크코스에 들어와서 처음 접해보았다.

그런데 생각보다 클로저가 코드 속에서 많이 쓰이고 있어 더 늦기 전에 한 번 정리를 하고 지나가고자 한다.

closure란?

클로저, 단어 그대로의 뜻을 풀이하자면 폐쇄, 종료 라는 뜻을 가지고 있다.

프로그래밍 적으로 뜻을 좀 더 풀이 해보자면, 함수와 그 함수가 선언될 당시의 Lexical Environment의 상호관계에 따른 현상이라고 한다.

그런데 이 정의에서 낯선 용어들이 보인다.

렉시컬 환경

렉시컬 환경은 어떤 뜻이고 이것의 관계에 따라서 어떤 현상이 나타나는 걸까?

lexical Scope = 정적 스코프

프로그래밍 언어에서 함수의 상위 스코프를 정하는 방법에는 크게 두가지가 있다.

첫번째로는, 동적 스코프 이다.

함수가 정의되는 시점에서는, 함수가 어디에서 호출이 될지 모른다. 그래서 동적 스코프는 함수를 호출하는 시점에 따라 스포크를 결정한다.

두번째로는, 정적 스코프 이다.

동적 스코프와 달리, 함수 정의가 평가된 시점에서 상위 스코프를 정적으로 결정한다. 그리고 함수가 어디에서 호출되냐에 상관없이, 정적으로 결정된 스코프를 활용한다.

그리고 자바스크립트의 경우 정적 스코프를 따르고 있다.

자바스크립트의 경우 코드를 실행하기전, 코드 평과 과정을 거친다.
이때에 정적 스코프의 방식에 따라 함수의 상위 스코프에 대한 참조가 이루어지는데 고려되는 것은 함수가 어디서 호출이 될 것인지가 아닌 어디서 선언이 되었냐 이다.

해당 과정을 거치면서 만들어지는 각각의 함수들의 상위 스코프에 대한 정보를 관리하는 곳이 lexical Environment이다.

closure 예시 와 함께 이해해보기

lexical Environment에 대해서 알아보았지만 closure에 대한 개념이 전혀 감이 잡하지 않는다.

정적으로 함수 상위 스코프를 결정하는 것이 어떤 특징을 가져온다는 말인가?

다음의 예시를 통해서 좀 더 자세히 살펴보자

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

해당 경우에서 inner함수에서 콘솔로 찍히는 부분은 에러가 나지 않을까?

inner 함수 내부에서는 변수 a라는 값이 선언되어 있지 않고, outer 함수에 변수 a가 선언되어 있는데 말이다.

정답은 에러가 나지 않고 1에 값이 더해진 2가 출력 되게 된다!

이유는 앞서 말한 렉시컬 환경과 연관이 있다!

정적으로 함수가 평가 될때에, outer의 경우 자신을 감싸고 있는 요소가 없기 때문에 자신의 상위 스코프로 전역스코프를 기억하게 된다.

inner의 경우에는 자신을 감싸고 있는 outer함수가 상위 스코프이기 때문에 outer에 관해서 기억하고 있게 된다.

그리곤 inner 함수에서 ++a를 실행하기 위해 변수a를 inner함수 내에서 찾는다.
하지만 찾을 수 없다.
그러면 자바스크립트는 다음 단계인 렉시컬 환경에 저장이 되어 있는 상위 컨텍스트로 저장된 outer내에서 변수 a를 찾아보게 된다.

outer함수에서는 변수 a값이 선언이 되어 있기 때문에, inner함수는 해당 값을 활용하여 에러를 발생시키지 않고 코드에 입력된데로 역할을 수행할 수 있다.

이제 inner함수는 outer와 inner함수가 어디에서 호출이 되었음에 상관이 없이, outer함수 내에 선언되어 있는 변수 a값에 접근할 수 있다.

그리고 한 가지 더, 재밌지는 점이 있다.

앞선 코드에서도 이를 발견할 수 있는데, 현재 outer함수의 경우 inner함수를 호출하는 코드가 실행됨과 동시에 함수의 실행이 종료되었다.

그렇기 때문에, outer함수에 대한 렉시컬 환경도 제거되어야 한다.

하지만, inner에서는 outer의 변수 a에 접근할 수 있다.
이미 실행이 종료되어 끝나고 사라져야 하는데도!

이는, 가비지 컬렉터의 동작 방식때문이다.
가비지 컬렉터는 어떤 값을 참조하는 변수가 하나라도 있다면, 그 값을 수집 대상에 포함하지 않는다.

위와 같은 경우도 outer가 끝가진 하였지만, inner함수에서 outer의 렉시컬 환경을 활용하기 때문에 이를 제거하지 않는다. 그래서 inner함수 내부에서 outer의 변수를 사용할 수 있는 것이다.

이처럼, 클로저란 어떤 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달 할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상을 말한다.

(클로저를 왜 사용하는지 와 관련해서는 다음 포스팅에 다룰 예정이다!)

0개의 댓글