24장 클로저

Yuri Lee·2021년 5월 27일
0
post-custom-banner

클로저는 자바스크립트 고유의 개념이 아니다. 함수를 일급 객체로 취급하는 함숭여 프로그래밍 언어(Haskell, Lisp, Erlng, Scala 등)에서 사용되는 중요한 특성이다.

24.1 렉시컬 스코프

  • 자바스크립트 엔진은 함수를 어디서 호출했는지가 아니라 함수를 어디에 정의했는지에 따라 상위 스코프를 결정한다. 이를 렉시컬 스코프(정적 스코프)라 한다.
  • 렉시컬 환경의 "외부 렉시컬 환경에 대한 참조"에 저장할 참조값, 즉 상위 스코프에 대한 참조는 함수 정의가 평가되는 시점에 함수가 정의된 환경(위치)에 의해 결정된다.

24.2 함수 객체의 내부 슬롯 [[Environment]]

  • 함수는 자신의 내부 슬롯 [[Environment]] 에 자신이 정의된 환경, 즉 상위 스코프의 참조를 저장한다.
  • 함수 객체의 내부 슬롯 [[Environment]] 에 저장된 현재 실행 중인 실행 컨텍스트의 렉시컬 환경의 참조가 바로 상위 스코프다.

24.3 클로저와 렉시컬 환경

function foo() {
  const x = 1;
  const y = 2;

  // 클로저
  // 중첩 함수 bar는 외부 함수보다 더 오래 유지되며 상위 스코프의 식별자를 참조한다. 
  function bar() {
    debugger;
    console.log(x);
  }
  return bar;
}

const bar = foo();
bar();
  • 외부 함수보다 중첩 함수가 더 오래 유지되는 경우 중첩 함수는 이미 생명 주기가 종료한 외부 함수의 변수를 참조할 수 있다. 이러한 중첩 함수를 클로저라고 부른다.
  • 클로저는 중첩 함수가 상위 스코프의 식별자를 참조하고 있고 중첩 함수가 외부 함수보다 더 오래 유지되는 경우에 한정하는 것이 일반적이다.
  • 클로저란 함수가 자유 변수에 대해 닫혀있다는 의미이다.
    • 클로저에 의해 참조되는 상위 스코프의 변수를 자유 변수라고 함 (ex. 위의 코드에서 x에 해당)
  • js 엔진은 최적화가 잘 되어 있어서 클로저가 참조하고 있지 않는 식별자는 기억하지 않는다.

24.4 클로저의 활용

  • 클로저는 상태를 안전하게 변경하고 유지하기 위해 사용한다. 상태가 의도치 않게 변경되지 않도록 상태를 안전하게 은닉하고 특정 함수에게만 상태 변경을 허용하기 위해 사용한다.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>

        // 함수를 인수로 전달받고 함수를 반환하는 고차 함수
        // 이 함수는 카운트 상태를 유지하기 위한 자유 변수 counter를 기억하는 클로저를 반환한다. 
        function makerCounter(predicate) {
            // 카운트 상태를 유지하기 위한 자유 변수
            let counter = 0;

            // 클로저를 반환
            return function () {
                // 인수로 전달받은 보조 함수에 상태 변경을 위임한다. 
                counter = predicate(counter);
                return counter;
            };
        }
        // 보조 함수
        function increase(n) {
            return ++n;
        }

        //보조 함수
        function decrease(n) {
            return --n;
        }

        // 함수를 함수로 생성한다.
        // makerCounter 함수는 보조 함수를 인수로 전달받아 함수로 반환한다. 
        const increaser = makerCounter(increase);
        console.log(increaser());
        console.log(increaser());

        // increaser 함수와는 별개의 독립된 렉시컬 환경을 갖기 때문에 카운터 상태가 연동하지 않는다. 
        const decreaser = makerCounter(decrease);
        console.log(decreaser());
        console.log(decreaser());
        console.log(decreaser());
        console.log(decreaser());
        console.log(decreaser());
        console.log(decreaser());
        console.log(increaser());
        console.log(increaser());

    </script>
</body>
</html>

24.5 캡슐화와 정보 은닉

  • 캡슐화는 객체의 상태를 나타내는 프로퍼티와 프로퍼티를 참고하고 조작할 수 있는 동작인 메서드를 하나로 묶는 것을 말한다.
  • 객체의 특정 프로퍼티나 메서드를 감출 목적으로 사용하기도 하는데 이를 정보 은닉이라고 한다.
  • 객체지향 프로그래밍 언어는 클래스를 정의하고 그 클래스를 구성하는 멤버에 public, private, protected 같은 접근 제한자를 선언하여 공개 범위를 한정할 수 있다.
  • JS 객체의 모든 프로퍼티와 메서드는 기본적으로 외부에 공개되어 있다. (모두 public!⭐⭐)

24.6 자주 발생하는 실수

  • var 키워드로 사용하지 않은 ES6의 반복문(for..in, for..of, while..) 등은 코드 블록을 반복 실행할 때마다 새로운 렉시컬 환경을 생성하여 반복할 당시의 상태를 마치 스냅숏을 찍는 것처럼 저장한다.

🌳 느낀점

  • 클로저..어렵ㄷr..다시 꼭 봐야되겠다. 🙄🙄

위 글은 위키북스의 모던 자바스크립트 Deep Dive 를 읽고 정리한 내용입니다.

profile
Step by step goes a long way ✨
post-custom-banner

0개의 댓글