TIL - Closure

정경훈·2021년 12월 7일
1

1. Closure란 무엇인가?


MDN ver.
함수와 그 함수가 선언될 당시의 Lexical enviroment의 상호관계에 따른 현상



youtube ver
함수와 Lexical Environment의 조합이고, 함수가 생성될 당시 외부 변수를 기억하여, 생성 후에도 계속 접근이 가능한 기능이다.

자바스크립트는 Lexical Environment를 갖는데, 코드가 실행되면 스크립트 내부에서 선언된 변수들이 Lexical Environment로 올라간다.



코어자바스크립트 ver
"어떤 함수 A에서 선언한 변수 a를 참조하는 내부함수 B를 외부로 전달할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않은 현상"


Lexical Environment

렉시컬환경 구분

  • 환경 레코드(Enviroment Record) : 모든 지역 변수를 프로퍼티로 저장하고 있는 객체로 this 값과 같은 기타정보도 모두 저장된다.

  • 외부 렉시컬 환경(Outer Lexical Environment) : 외부 코드와 연관됨

자바스크립트의 함수는 숨김 프로퍼티인 [[Environment]] 를 이용해 자신이 어디서 만들어졌는지를 기억하고 함수의 내부 코드는 [[Environment]]를 사용해 외부 변수에 접근한다.

2. 간단한 예시코드

(1) 외부 변수를 참조하는 함수

먼저, let으로 선언된 변수는 호이스팅이 되지만 초기화가 되지 않아 컴퓨터가 읽어내기 전에는 사용이 불가하다.

하지만, 함수 선언문은 바로 초기화가 되어 어느 위치에서나 사용이 가능하다는 것을 알아두면 좋을 것 같다. (초기상대 greetings : 사용불가 / sayHello : 사용가능)

현재 상태에서 전역 Lexical Environment는 greetingssayHello이다. 이때, greetings 는 "안녕하세요" sayHello는 함수를 가지게 된다.

sayHello라는 함수가 실행되면 내부 Lexical Environment이 발생하게 되는데, 이때 내부 Lexical Environment의 name은 "경훈"이 된다.

하지만, 함수가 실행됨과 동시에 내부환경에서 name만을 찾을 수 있고 greetings라는 값을 찾지 못하게 된다.

이때, greetings라는 값을 찾기위해 외부 Lexical Environment로 나가게 되는데 현재는 외부의 환경이 전역 Lexical Environment 환경이기 때문에 전역환경에서 값을 찾게 된다.

전역환경을 참조하여 greetings의 "안녕하세요" 라는 값을 알게된 sayHello는 최종적으로 '안녕하세요경훈' 이라는 값을 출력할 수 있게 된다.

이렇게 내부함수에서 외부 변수를 참조하는 경우를 "선언될 당시의 LexicalEnvironment와의 상호관계"라고 볼 수 있다.

(2) 외부 변수를 참조하는 내부 함수

outer 함수에서 변수 a를 선언하고, inner함수에서 a의 값을 1만큼 증가시켰다.

하지만, inner안에서 a는 선언된 것이 없어 값을 찾을 수 없다. 그렇기 때문에 a를 찾기 위해서 상위 outer를 참조하여 a를 찾아내 2라는 값을 추출해낸다.

마지막으로, 이 예시는 outer 함수의 실행 컨텍스트가 종료되기 전 inner 함수의 실행 컨텍스트가 종료 되었기 때문에 inner 함수를 호출할 수 없다.

첫 예시와는 다르게 두번째 예시에서는 inner 함수를 그대로 반환하는 예시이다.

outer 함수가 종료될 때, outer2 변수inner 함수를 참조하게 된다. 이후 outer2를 호출하면 inner 함수가 실행된다.

inner 함수는 이제 선언된 위치의 LexicalEnvironment(outer함수의 환경)가 참조되어 a에 접근한 뒤 2를 반환할 것이다.

그런데 이때, 다시 outer2 변수를 호출하면 반환된 2를 참조하여 1을 증가시킨 후 3이 반환되는 것을 볼 수 있다.

이는 가비지컬렉터의 동작 방식 때문인데, 어떤 값을 참조하는 변수가 하나라도 존재하면 그 값은 가바지 컬렉터의 수집 대상에서 제외되기 때문이라고 한다. 그리고 위의 예제가 가비지 컬렉터의 수집대상에서 제외되는 유일한 상황이라고 한다.

(3) return 없이도 클로저가 발생하는 경우

window의 메서드(setTimeout 또는 setInterval)에 전달할 콜백 함수 내부에서 지역변수(inner, intervalId)를 참조하고 있기 때문에 클로저가 발생한다.

출처

웹사이트
https://www.youtube.com/watch?v=tpl2oXQkGZs
https://ko.javascript.info/closure
https://dev-kimse9450.tistory.com/77

도서
코어자바스크립트(위키북스) 5장 클로저

profile
발전하고 싶은 프론트엔드 개발자 입니다 :)

0개의 댓글