본문 바로가기

개인공부 기록/JavaScript

[JavaScript] 클로저(Closuer)

혼자 공부하고 정리해보려 하였으나.. 아직은 어려운 개념인 거 같아 글 하나를 읽고 정리해보는 방식으로 포스팅을 한다

나중에 좀 더 익숙해지면 그때 나만의 정의로 정리를 시도해봐야겠다.

 

출처(원문)

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

 

자바스크립트의 스코프와 클로저 : NHN Cloud Meetup

자바스크립트의 스코프와 클로저

meetup.toast.com

 

이번 게시글에 사용된 코드 예제 및 대부분의 사진, 내용 등은 위 출처에서 가져와 사용하였습니다.

MDN에 적힌 클로저의 정의

사실 처음 클로저의 정의를 보았을 때 이게 무슨 소리지? 싶었습니다. 함수가 선언된 어휘적 환경, 함수가 생성된 시점을 기억한다, 폐쇄공간 등 구글링을 하다 보니 다른 분들이 각자 자신만의 언어로 정의 내린 클로저의 정의를 접하다 보니 더욱 헷갈리기만 할 뿐이었습니다. 여러 번 곱씹어 생각하다 보니 신기하게도 이해가 갔는데요 처음 클로저라는 개념을 접하시는 분들에게 이렇게 설명해드리면 이해가 잘 될 것 같다고 생각하는 부분이 있어 일부 가져와보았습니다.

 

아래 코드는 클로저를 설명하기 위한 예시 코드입니다.

var color = 'red';
function foo() {
    var color = 'blue'; // 2
    function bar() {
        console.log(color); // 1
    }
    return bar;
}
var baz = foo(); // 3
baz(); // 4
  1. bar는 color를 찾아 출력하는 함수로 정의되었다.
  2. 그리고 bar는 outer environment 참조로 foo의 environment를 저장하였다.
  3. bar를 global의 baz란 이름으로 데려왔다.
  4. global에서 baz(=bar)를 호출했다.
  5. bar는 자신의 스코프에서 color를 찾는다.
  6. 없다. 자신의 outer environment 참조를 찾아간다.
  7. outer environment인 foo의 스코프를 뒤진다. color를 찾았다. 값은 blue이다.
  8. 때문에 당연히 blue가 출력된다.

위의 코드는 클로저를 설명한 예시인데요, 그냥 단순하게 보면 "이게 왜?"라고 생각하실 수 있지만 하나씩 살펴보겠습니다. 일단 중요한 부분은 2~4번, 그리고 7번인데요. bar는 자신이 생성된 렉시컬 스코프에서 벗어나 global에서 baz라는 이름으로 호출이 되었고, 스코프 탐색은 현재 실행 스택과 관련 없는 foo를 거쳐 갔습니다. baz를 bar로 초기화할 때는 이미 bar의 outer lexical environment를 foo로 결정한 이후입니다. 때문에, bar의 생성과 직접적인 관련이 없는 global에서 아무리 호출하더라도 여전히 foo에서 color를 찾게 되죠 이런 bar(또는 baz)와 같은 함수를 우리는 클로저라고 부릅니다.

여기에서 다시 한번 강조하지만 JS의 스코프는 렉시컬 스코프, 즉 이름의 범위는 소스코드가 작성된 그 문맥에서 바로 결정됩니다.

추가로, foo의 렉시컬 환경 인스턴스는 foo();수행이 끝난 이후 GC(Garbage Colletor)가 회수해야 하는데 사실을 그렇지 않습니다. 앞에 설명했듯 bar는 여전히 바깥 렉시컬 환경인 foo의 렉시컬 환경을 계속 참조하고 있고, 이 bar는 baz가 여전히 참조하고 있기 때문이죠.(baz(=bar) -> foo)

 

내부 함수가 종료되었음에도 baz()를 통하여 bar()의 외부 함수에 접근할 수 있다.

bar()가 선언된 시점과 그 환경(console에 color를 출력한다)을 기억한다.

 

Recent Posts
Popular Posts
Recent Comments