클로저

ken6666·2024년 3월 5일
0

JS

목록 보기
20/39

클로저란?

const x = 1;

function outerFunc() {
  const x = 10;

  function innerFunc() {
    console.log(x); // 10
  }// innerFunc과 outerFunc 사이는 클로저

  innerFunc();
} // outerFunc과 전역컨텍스트 사이의 클로저

outerFunc();

클로저는 내부 함수로부터 외부함수에의 접근 권한을 주며 이론적으로는 함수 생성 시점에 언제나 생긴다.

렉시컬 스코프

const x = 1;

function foo() {
  const x = 10;
  bar();
}

function bar() {
  console.log(x);
}

foo(); // 1
bar(); // 1

자바 스크립트 엔진은 함수를 어디서 호출했는지가 아니라 함수를 어디에 정의했는지에 따라 상위 스코프를 결정한다. 이를 렉시컬 스코프라 한다.

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

const x = 1;

function foo() {
  const x = 10;
  bar();
}

function bar() {
  console.log(x);
}

foo(); // 1
bar(); // 1

함수는 자신의 내부 슬롯 [[Environment]]에 작신이 정의된 환경, 즉 상위 스코프의 참조를 저장한다.

클로저와 렉시컬 환경

const x = 1;

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

// outer 함수를 호출하면 중첩 함수 inner를 반환한다.
// 그리고 outer 함수의 실행 컨텍스트는 실행 컨텍스트 스택에서 팝되어 제거된다.
const innerFunc = outer(); // ③ -> inner
innerFunc(); // ④ 10

외부 함수보다 중첩 함수가 더 오래 유지되는 경우 중첩 함수는 이미 생명주기가 종료한 외부 함수의 변수를 참조할 수 있다. 이러한 중첩 함수를 클로저라고 한다.

  • 예시에서 outer 함수의 실행 컨텍스트는 실행 컨텍스트 스택에서 제거되지만 outer 함수의 렉시컬 환경까지 소멸되지 않는다.
  • 누군가 참조하고 있다면 가비지 컬렉터는 메모리 공간을 함부로 해제하지 않는다.

클로저의 활용

// 카운트 상태 변수
let num = 0;

// 카운트 상태 변경 함수
const increase = function () {
  // 카운트 상태를 1만큼 증가 시킨다.
  return ++num;
};

console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3

위의 예시의 카운트 상태는 전역 변수를 통해 관리되고 있기때문에 언제든지 누구나 접근할 수 있다.

이는 오류를 발생시킬 가능성이 있는 좋지 않은 코드다

// 카운트 상태 변경 함수
const increase = (function () {
  // 카운트 상태 변수
  let num = 0;

  // 클로저
  return function () {
    // 카운트 상태를 1만큼 증가 시킨다.
    return ++num;
  };
}());

console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3
  • 클로저는 상태를 안전하게 변경하고 유자하기 위해 사용한다.
  • 상태를 안전하게 은닉하고 특정 함수에게만 상태 변경을 허용하기 위해 사용한다.

0개의 댓글