자바스크립트의 closoure 가 뭐죠?

우현민·2022년 11월 18일
2

javascript

목록 보기
4/5

자바스크립트의 클로저는 참 이해하기 어려운 친구입니다. 실체가 잘 보이지도 않고, 인터넷을 검색해봐도 다들 조금씩 애매하게 설명하고 있습니다.

유명한 아래 사이트/책 들은 아래와 같이 클로저를 설명합니다.

MDN
클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다.

w3schools
전역 변수는 클로저를 통해 로컬이 될 수 있다.

you don't know JS
클로저는 함수가 속한 렉시컬 스코프를 기억하여 함수가 렉시컬 스코프 밖에서 실행될 때에도 이 스코프에 접근할 수 있게 하는 기능을 뜻한다.

위키백과
클로저(Closure)는 일급 객체 함수(first-class functions)의 개념을 이용하여 스코프(scope)에 묶인 변수를 바인딩 하기 위한 일종의 기술이다.

이렇듯 모호하고 다양한 설명들 덕에 항상 헷갈렸었는데, 다 읽고 보니 개인적으로는 you don't know JS 의 설명이 가장 명확하다고 느껴졌습니다. 그럼 시작해 보겠습니다!



이론

function foo () {
  const a = 1;
  
  function bar () {
    console.log(a);
  };
  
  bar();
};

console.log(a); // ❌ 불가능!
foo(); // ✅ 1

위 코드에서 foo 를 수행하는 곳에서는 a를 알지 못합니다. 하지만 함수 foo 를 수행하면 1이 출력됩니다. 즉 bar 가 수행될 때, bara 에 대해 알고 있습니다. 자바스크립트가 스코프를 처리하는 방식에 의해, foo 는 자신의 스코프에서 먼저 a 라는 변수를 찾아보고, 없으니 한칸 올라가서 전역 스코프에서 a 를 발견합니다.

이건 우리가 아는 스코프에 대한 이야기입니다. 하지만 이것도 클로저라는 추상적인 기능 중 일부입니다.

이렇게만 설명하면 "그건 렉시컬 스코프의 기능 아닌가? bar 는 foo 안에 있으니 당연히 되어야지!" 라는 생각이 들고 알쏭달쏭하기 때문에, 조금 더 명확한 예제를 보겠습니다.

function foo () {
  const a = 1;
  
  function bar () {
    console.log(a);
  };
  
  return bar;
};

const baz = foo(); // bar
baz(); // 1

이 경우는 조금 더 명확합니다. baza 에 대해 전혀 알지 못하지만, a 의 값을 잘 출력했습니다. baz 가 선언된 곳에는 a에 대한 정보가 전혀 없는데, 어떻게 a 를 찾을 수 있었을까요?

이게 클로저의 역할입니다. 모든 함수는: 어디서 수행되든, 자신이 선언된 곳의 스코프를 통째로 기억합니다.

크롬의 개발자 도구 콘솔에서는 아래와 같이 클로저의 존재를 확인할 수 있습니다. baz 를 출력했을 때, baz.[[Scopes]][0] 에 클로저가 있습니다.



코드

우리가 일반적으로 쓰는 코드들을 볼까요? 아래는 평범한 리액트 코드입니다.

const Counter = () => {
  const [count, setCount] = useState(0);
  
  const handleClick = () => {
    setCount(count + 1);
  };
  
  return <button onClick={handleClick}>{count}</button>;
};

위 코드에서, handleClick 은 버튼을 클릭했을 때 이벤트 핸들러를 통해 실행됩니다. 그곳에서는 count 에 접근할 수 없지만, handleClick 함수가 클로저를 통해 count 에 접근할 수 있기 때문에 코드가 정상적으로 동작합니다.

이렇듯 클로저는 우리가 작성하는 모든 코드에 자연스럽게 녹아 있습니다. 외부 스코프의 변수를 사용하도록 작성한 모든 함수는 클로저 스코프를 포함합니다. 그리고 그 함수가 선언된 스코프 밖에서 실행된다면, 그 함수는 클로저를 이용합니다.

클로저 스코프에 변수가 존재하더라도, 함수가 선언된 스코프에서 실행된다면, 클로저를 이용한다고 표현하기는 조금 애매합니다. You don't know JS 에서는 해당 경우는 클로저가 작용한 예는 아니지만, 클로저와 연관이 깊다 라고 설명합니다.



결론

클로저는 우리가 작성하는 대부분의 코드에 함께 살아 숨쉬는 친구입니다. 한 마디로 정의하자면, 함수가 어디서 수행되든 선언된 곳의 렉시컬 스코프를 기억할 수 있는 기능 입니다.

이런 클로저를 통해 우리는 자바스크립트 코드를 짤 때 스코프에 대한 걱정 없이 함수를 값으로 이리저리 넘기고 래핑하고 콜백으로 전달하는 등의 행동을 자유롭게 할 수 있습니다. 함수를 일급 객체로 다루고 그 이점을 활용하기 위해 필수적인 기능이라고 할 수 있겠습니다.

profile
프론트엔드 개발자입니다

0개의 댓글