자바스크립트 핵심컨샙33 #21. Closure

김동욱·2021년 6월 27일
0

자바스크립트

목록 보기
21/25

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

feat.MDN

무슨말인지 잘 모르겠습니다. 번역기를 돌려보면

closure

  1. (공장·학교·병원 등의 영구적인) 폐쇄(되는 상황)
    factory closures
  2. (도로·교량의 일시적) 폐쇄
  3. (힘든 일의) 종료

어떠한 것을 '닫다, 마무리하다'는 뜻인것같습니다.


번역해도 뭔말인지 모르겠습니다.

일단 코드를 보겠습니다.

function makeCounter(predicate) {
  let num = 0;

  return function () {
    num = predicate(num);

    return num;
  };
}

function increase(n) {
  return ++n;
}

const inc = makeCounter(increase);//객체화

console.log(inc());//1
console.log(inc());//2
console.log(inc());//3

일반적인 상식으로는 inc함수를 호출할때마다 makeCounter안에 있는 지역 변수인 num이 '초기화'가 되야하는데 inc함수를 호출할때마다 1씩 ++되고있습니다.

왜 이런 현상이 발생하냐면

모든 함수는 함수가 생성된 곳의 렉시컬 환경을 기억합니다. 함수는 Environment라 불리는 숨김 프로퍼티를 갖는데, 여기에 함수가 만들어진 곳의 렉시컬 환경에 대한 참조가 저장됩니다.
feat. Javascript.Info

즉 Environment프로퍼티 덕분에 inc.Environment엔 num = 0이 있는 렉시컬 환경에 대한 참조가 저장됩니다.

호출 장소와 상관없이 함수가 자신이 태어난 곳을 기억할 수 있는 건 바로 이 Environment 프로퍼티 덕분입니다. Environment는 함수가 생성될 때 딱 한 번 값이 세팅되고 영원히 변하지 않습니다.

inc()를 호출하면 각 호출마다 새로운 렉시컬 환경이 생성됩니다. 그리고 이 렉시컬 환경은 inc.Environment에 저장된 렉시컬 환경을 외부 렉시컬 환경으로서 참조합니다. 그래서 inc함수가 밖에서 호출되도 makeCounter의 내부변수가 인식했던 외부변수 num의 Environment의 참조능력? 때문에 값을 변화시킬 수 있는것입니다.

즉 클로저란

실행되는 내부함수가 환경밖에서 호출되더라도

자신이 선언되는 환경이 되었을때의 스코프를 기억하여

그 환경에 접근할 수 있는 함수를 말합니다.


하지만 클로저는 자신이 생성될 때의 환경을 기억해야 하므로 메모리 차원에서 손해를 볼 수 있습니다.
하지만 클로저는 강력한 기능으로 이를 적극적으로 사용해야 합니다.

클로저 함수의 또 다른 예시를 보겠습니다.

const btn = document.querySelector('button');

function toggle(){
    let num = 0;

    return function(){
        ++num;
        console.log(num)
    }
}

btn.addEventListener('click', toggle())//1,2,3...

토글이란 함수를 만들고 내부함수로 변수num이 ++되는 기능을 리턴하고있습니다. 그리고 이벤트핸들러에 할당하였습니다.
버튼을 클릭하면 숫자가 올라가는 코드로 자주 보는 모양입니다. 이 코드에는 장점이 있습니다.

이 코드의 장점은 첫째 상태유지입니다.😍

위에서 설명했듯 toggle안의 내부함수가 리턴이 되면 내부함수가 자신이 선언되었을때를 기억하여 num변수의 값을 계속 변화 시키고 상태를 계속 유지할 수 있습니다.
지금은 이벤트 핸들러에 toggle함수를 할당했기때문에 클로저가 기억하는 렉시컬 환경의 변수 num은 소멸하지않습니다.

또 하나의 장점은 전역변수를 억제했다는 것입니다.😍

보통 위같은 코드를 작성할때에는 변화하는 변수(위에서는 num변수가 되겠네요)를 보통 글로벌 스코프에 작성합니다.
하지만 만약 나중에 누군가가 num 변수 네임을 나중에 뒤에서 모르게 작성을 해버리면? 갑자기 발생하는 오류에 파일을 뒤지고 야근하는겁니다.😴
그러한 멘붕과 야근을 억제하기위해서 최대한 중복되는 네임을 피해야합니다.
하지만 클로저를 사용하면 외부환경에서의 접근을 막을 수 있고 변수 네이밍 중복을 막을 수 있습니다.

마지막으로는 재사용의 유용성입니다.😍

이것은 모든 코드가 공통으로 추구해야하는 내용이지만 클로저 함수는 자신만의 환경을 가지면서 외부환경으로 부터 안전하기 때문에 다른 함수보다 더 단단하고 유지보수하기가 수월합니다.


클로저는 어려운 개념입니다.

하지만 이론만 명확히 알면 자바스크립트 스킬을 한단계 더 올릴 수 있는 좋은 발판이 됩니다!

profile
안녕하세요. 부산에서 근무하고 있는 프론트엔드 개발자 김동욱입니다. 영어 공부 겸 개발 공부를 위해서 글을 작성하고있습니다.

0개의 댓글