클로저 알아보기 [모던 자바스크립트 Deep Dive : 24장]

조성원·2023년 4월 12일
0
post-thumbnail

난해한 클로저 개념 요약

클로저는
함수와 그 함수가 선언된 렉시컬 환경과의 조합으로,

자신이 선언될 당시의 환경을 기억하는 함수입니다.

해당 함수의 생명 주기가 종료되더라도
함수의 반환된 값이 변수에 의해 아직 참조되고 있다면
렉시컬 환경에 남아 참조가 가능하다는 특징이 있습니다.



아래 코드를 통해 클로저 개념을 더 살펴보겠습니다.

const x = 1;

function outer() {
  const x = 10;
  const inner = function () { console.log(x); };
  return inner;
}

// outer 함수를 호출하면 중첩 함수 inner를 반환합니다
const innerFunc = outer();
innerFunc() // 10

const innerFunc = outer()

여기서 outer()를 호출하면 outer 함수는
중첩 함수인 inner를 반환하고 생명 주기를 마감합니다.

이 때, outer 함수의 지역 변수 x 또한 생명 주기를 마감합니다.

하지만 innerFunc() //10 을 통해
지역 변수 x에 접근이 가능한 것을 확인할 수 있습니다.

이처럼 외부 함수보다 내부 함수가 더 오래 유지 되는 경우,
내부 함수는 이미 생명 주기가 종료된 외부 함수의 변수를 참조할 수 있습니다.




클로저의 활용

클로저는
상태(state)를 안전하게 변경하고 유지하기 위해 사용합니다.

즉, 상태가 의도치 않게 변경되지 않도록 상태를 은닉하고
특정 함수에게만 상태변경을 허용하기 위해 사용합니다.



아래 코드를 통해 활용 사례를 더 살펴보겠습니다.

안전한 상태 변경

<!DOCTYPE html>
<html>
<body>
  <div class="box" style="width: 100px; height: 100px; background: green;"></div>

  <script>
    // Box Color Toggler
    const box = document.querySelector('.box');

    const toggleColor = (function () {
      let isGreen = true;
      // 클로저 반환
      return function () {
        box.style.background = isGreen ? 'red' : 'green';
        // 상태 변경
        isGreen = !isGreen;
      };
    })();
    // 박스 클릭 이벤트
    box.addEventListener('click', toggleColor);
  </script>
</body>
</html>

toggleColor 함수의 내부 함수에서
box.style.background 속성을 바꿔주는 작업이 이뤄지고 있습니다.

여기서 전역 변수를 사용하지 않고도,
클로저의 개념을 활용하여 상태를 변경하는 것이 가능합니다.

이처럼 클로저의 개념을 활용하면,
외부의 의도되지 않은 접근으로부터 안전하게
상태를 변경할 수 있다는 장점이 있습니다.



프라이빗 메서드

또, 프라이빗 메서드(Private method)를 만들 수 있습니다.
같은 클래스 내부의 다른 메소드에서만 그 메소드를 호출할 수 있습니다.

var makeCounter = function() {
      var privateCounter = 0;
      function changeBy(val) {
        privateCounter += val;
      }
      return {
        increment: function() {
          changeBy(1);
        },
        decrement: function() {
          changeBy(-1);
        },
        value: function() {
          return privateCounter;
        }
      }
    };

    var counter1 = makeCounter();
    var counter2 = makeCounter();
    alert(counter1.value()); /* 0 */
    counter1.increment();
    counter1.increment();
    alert(counter1.value()); /* 2 */
    counter1.decrement();
    alert(counter1.value()); /* 1 */
    alert(counter2.value()); /* 0 */

다음과 같이 카운터 함수를 만들었습니다.
카운터 함수의 내부 메서드로는
increment, decrement, value 가 있습니다.

이 세 메서드는 같은 환경을 공유하는 클로저입니다.

클로저의 개념을 활용하여,
두 개의 인스턴스가 각각의 독립성을 유지할 수 있습니다.

각 카운터가 호출될 때마다
하나의 클로저에서 변수 값을 변경해도
다른 클로저의 값에는 영향을 주지 않게 됩니다.


function Counter() {
  let counter = 0;
  this.increase = function () {
    return ++counter;
  };
  this.decrease = function () {
    return --counter;
  };
}
const counter = new Counter();

이는 생성자 함수를 이용해도
똑같이 구현할 수 있습니다.


캡슐화

캡슐화
클래스 안에 서로 연관있는 속성과 기능들을 하나의 캡슐로 만들어
데이터를 외부로부터 보호하는 것을 말합니다.

  • 데이터 보호: 외부로부터 클래스에 정의된 속성과 기능들을 보호
  • 데이터 은닉: 내부의 동작을 감추고 외부에는 필요한 부분만 노출



클로저가 생성되는 경우

  1. 내부 함수가 익명 함수로 되어 외부 함수의 반환값으로 사용될 때
  2. 내부 함수가 외부 함수의 스코프에서 실행될 때
  3. 내부 함수에서 사용되는 변수외부 함수의 변수 스코프에 포함되어 있을 때
profile
IT 트렌드에 관심이 많은 프론트엔드 개발자

0개의 댓글