Skip to content

클로저란?

jhleeWEB edited this page Jun 21, 2022 · 3 revisions

어휘적 범위 지정 (Lexical scoping)

Lexical

어휘적 범위를 지정하는 과정에서 변수가 어디에서 사용 가능한지 알기 위해 그 변수가 소스코드 내 어디에서 선언되었는지를 고려한다는 의미

Closure

함수가 부모 함수 내에 선언되었다면 그 자식 함수가 closure이다. 클로저의 특징

  • 외부함수 스코프에서 내무함수 스코프로 접근 불가능하다.
  • 반대로 내무함수는 외부함수 스코프에 접근이 가능하다.
  • 외부함수의 실행이 종료된 후에도, 클로저는 외부함수의 스코프에 접근 할 수 있다.

이제 대충 뭔지 알았으니 왜 알아야하는지도 알아야지

우선 대표적으로 react에서의 클로저를 살펴보자

const Component = () => {
  const [count, setCount] = useState(0);
  
  const increment = () => {
    setCount(count + 1);
  }
  useEffect(() => {
    const timer = setTimeout(() => increment(), 1000);

    return () => clearTimeout(timer);
  },[increment]);

  return <div>{count}</div>
}

Component함수는 외부 함수가 될 것이고, increment함수는 내무 함수가 될 것이다. increment함수는 외부함수에서 선언된 지역변수 count에 1을 더하여 dispatch한다. 여기서 increment함수가 클로저이다. 이상황에서는 정상적으로 count올라가는 것을 경험할 수 있다.

그럼 increment함수를 useCallback훅을 활용했을때 어떻게 되는지 확인해보자

const Component = () => {
  const [count, setCount] = useState(0);
  
  const increment = useCallback(() => {
    setCount(count + 1);
  },[]);

  useEffect(() => {
    const timer = setTimeout(() => increment(), 1000);

    return () => clearTimeout(timer);
  },[increment]);

  return <div>{count}</div>
}

위에 코드를 실행하면 이전 현상과 다른 것을 경험할 수 있다. 이유는 useCallback훅을 사용하면서 기존에 increment함수가 더이상 Component의 어휘적 범위에 속하지 않게 된 것이기 때문이다. useCallback의 increment함수를 callback함수로 넘겨줬고, useCallback을 그 callback함수를 감쌓아서 반환해 줬을 것이다. 그렇게 된다면 감싸고있는 함수는 callback의 외부 함수가 되고, callback은 내부함수가 될것이다.

const Component = () => {
  const [count, setCount] = useState(0);
  
  const increment = useCallback(() => {
    setCount(count + 1);
  },[count]);

  useEffect(() => {
    const timer = setTimeout(() => increment(), 1000);

    return () => clearTimeout(timer);
  },[increment]);

  return <div>{count}</div>
}

다시 정상적으로 작동하게 하려면 useCallback 참조배열에 count를 넣어줘야 한다. 그래야 useEffect가 increment의 변화를 감지하며 연속적으로 count가 올라갈것이다.