본문 바로가기
Programming Language/Javascript

[Javascript] 클로저

by ggyongi 2024. 6. 14.
반응형

 

* 클로저 이해를 위해선 '렉시컬 스코프'에 대한 이해가 선행되어야 한다.

 

 

클로저와 렉시컬 환경

const x = 1;

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

const innerFunc = outer();
innerFunc();

 

outer() 함수를 호출하면 inner를 반환하고 생명주기를 마감, 즉 실행 컨텍스트가 실행 컨텍스트 스택에서 제거된다. 이에 따라 이 outer 함수 내의 지역변수 x도 생명주기가 마감된다. 그런데 innerFunc()를 실행하면 결과로 10이 나온다.

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

 

이것이 가능한 이유는 실행 컨텍스트가 스택에서 제거될때 outer 함수의 렉시컬 환경까지 소멸되지는 않기 때문이다. outer 함수의 렉시컬 환경은 inner함수의 [[Environment]] 내부 슬롯에 의해 참조되고 있고 inner 함수는 전역 변수 innerFunc에 의해 참조되고 있으므로 가비지 컬렉션 대상이 되지 않는다.

 

 

클로저의 활용

클로저는 상태를 안전하게 변경하고 유지하기 위해 사용한다. 상태가 의도치 않게 변경되지 않도록 상태를 안전하게 은닉하고 특정 함수에게만 상태변경을 허용하기 위해 사용한다. 

 

let num = 0

const increase = function(){
  return ++num;
}

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

위의 코드는 num 변수를 어디서나 변경할 수 있어서 상태 유지에 안전하지 않다.

 

const increase = function(){
  let num = 0
  return ++num;
}

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

그렇다고 이렇게 변수를 함수 내 지역변수로 넣으면 은닉에는 성공하지만 값이 계속 0으로 초기화된다.

 

const increase = (function(){
  let num = 0;
  return function(){
    return ++num;
  };
}());

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

이렇게 클로저를 사용하면 은닉도 되고 상태 유지가 된다.


데이터 은닉 다른 예시

function createCounter() {
  let count = 0; // 외부에서 직접 접근 불가

  return {
    increment: function () {
      count++;
      console.log(count);
    },
    decrement: function () {
      count--;
      console.log(count);
    },
  };
}

const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.decrement(); // 1
// 외부에서 count 직접 접근 불가: console.log(counter.count); // undefined

 

 

 

비전공자 네카라 신입 취업 노하우

시행착오 끝에 얻어낸 취업 노하우가 모두 담긴 전자책!

kmong.com

댓글