본문으로 바로가기

Closure... Lexical Environment....

category JavaScript 2025. 1. 7. 00:17

클로저란 무엇이냐...

 

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives a function access to its outer scope. In JavaScript, closures are created every time a function is created, at function creation time.

 

Closures - JavaScript | MDN

A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives a function access to its outer scope. In JavaScript, closures are created every time

developer.mozilla.org

 

Closure(클로저)는 함수와 그 함수가 선언된 렉시컬 환경(Lexical Environment)을 묶어놓은 조합입니다. 간단히 말하면, 클로저는 함수가 자신의 외부 스코프(상위 스코프)에 접근할 수 있도록 해주는 기능이라고 합니다...

 

수업 자료에 왜 있는지 충분히 이해되는 사진...

 

이렇게 하면 이해가 안되니 먼저 Lexical Environment가 뭔지부터 알아봅시다.

const x = 1;

function outerFunc() {
  const x = 10;
  function innerFunc() {
    console.log(x); // 10
  }

  innerFunc();
}

outerFunc();

 

 

innerFunc 스코프 내에서 x 값은 존재하지 않으니 상위 스코프인 outerFunc로 이동해 x값을 참조합니다.  => scope chain

 

innerFunc의 outer는 outerFunc의 Lexical Environment이므로 x는 outerFunc()에서의 x 값이 10을 참조합니다.

 

 

 

그렇다면 아래의 예에서는 어떨까요?

const x = 1;

function outerFunc() {
  const x = 10;
  innerFunc(); // 1
}

function innerFunc() {
  console.log(x); // 1
}

outerFunc();

 

innerFunc가 outerFunc 내에서 실행되는데 x = 10이 안되냐....

바로 정의된 위치가 중요하기 때문입니다.(어디서 호출됐는지는 중요하지 않음)

innerFunc와 outerFunc는 서로 다른 스코프를 가지고 있어 변수를 공유할 수 없습니다. 

따라서 innerFunc의 x는 상위 스코프인 전역 Lexical Environment의 x를 참조합니다.

 

 

그럼 이제 클로저와 렉시컬 환경에 대해서 알아봅시다.

const x = 1;

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

const innerFunc = outer();
innerFunc();

 

먼저 실행 순서를 콜스택으로 보면

 

outer 함수가 실행된 후 빠져 나가고 그 후에 innerFunc가 실행되게 됩니다.

그럼 innerFunc의 x는 상위 스코프인 outer 함수의 x를 참조할까요? 아니면 전역 스코프의 x를 참조할까요?

outer가 실행된 후 스택에서 제거되어도 여전히 innerFunc의 outer는 outer 함수의 Lexical Environment입니다.

그 말인 즉슨, outer의 x를 참조하고 있다는 것입니다.


그러면 어떻게 outer 함수가 스택에서 제거되지만 Lexical Environment는 유지될 수 있을까요?

outer 함수가 실행되면 Activation Object가 생성되어 함수 내의 지역 변수인 x = 10을 저장합니다.

일반적으로 함수 실행이 끝나게 되면 이 객체는 가비지 컬렉션에 의해 제거되게 됩니다.

하지만!!! innerFunc의 x가 outer 함수의 x를 참조하고 있기 때문에 가비지 컬렉터x = 10이라는 Lexical Environment를 수거하지 않고 유지하게 됩니다.


 

이처럼, 클로저에서 Lexical Environment는 함수가 실행된 후에도 그 스코프 내의 변수를 참조하는 다른 함수가 있을 경우 계속해서 메모리에서 유지되며, 가비지 컬렉터에 의해 제거되지 않습니다

 

클로저를 이용한 count

function createCounter() {
  let count = 0;

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

const counter = createCounter();
counter(); // 1
counter(); // 2
counter(); // 3

 

위와 같이 클로저를 사용하면 count라는 변수 값을 바꿔줄 수 있는 것은 createCounter 내부의 함수입니다.

이처럼 메서드를 통해서만 데이터를 변경하거나 조회할 수 있어 데이터 은닉이 가능합니다.

 

이거 어디서 본 거 같지 않나요....?

바로 React의 useState도 비슷한 역할을 합니다!

const [count, setCount] = useState(0);

setCount(count + 1);

 

이렇게 setCount를 통해서만 count 값을 변경할 수 있는....

 

                           

어쨋든 가비지 컬렉터야 고마워

🧡