본문 바로가기
카테고리 없음

CH_24. 클로저

by 코딩기 2024. 5. 19.
728x90

클로저(closure)의 개념


“클로저는 ‘함수’와 그 함수가 ‘선언됐을 때의 렉시컬 환경’의 조합이다”

더보기

☝ 잠깐(wait)!! 렉시컬 환경이란?

→ 식별자와 식별자에 바인딩된 값, 상위 스코프에 대한 참조를 가리키는 자료구조

함수를 일급 객체로 취급하는 함수형 프로그래밍에서 없어서는 안될 중요한 특성

 

< 예시1 >

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

outerFunc(); // 10

실행 컨텍스트 관점

  • 호출 시 각각의 스코프 체인을 순차적으로 검색하여 상위 스코프에 접근하여 함수를 실행
    1. innerFunc 함수 내부에서 변수 x 검색 → 검색 실패!
    2. outerFunc 내부에서 변수 x 검색 → 검색 성공!

< 예시 2 >

function outerFunc() {
  const x = 10;
  const innerFunc = function () { console.log(x); };
  return innerFunc;
}
// 함수 outerFunc를 호출하면 내부 함수 innerFunc가 반환된다.
// 그리고 함수 outerFunc의 실행 컨텍스트는 소멸한다.
const inner = outerFunc();
inner(); // 10

실행 컨텍스트관점

  • inner에 outerFunc()를 할당한 시점에서 outerFunc()의 실행 컨텍스트는 종료, 하지만 inner()를 실행할 시 그대로 동작함
    1. outerFunc() 호출 시, 실행컨텍스트 생성 및 innerFunc() 반환
    2. innerFunc는 외부 함수인 outerFunc의 x변수 참조 (클로저)
    3. 클로저 덕분에 innerFunc 반환 후 outerFunc의 실행 컨텍스트는 유지
    4. 따라서 다른 변수에 할당하여 컨텍스트가 종료되더라도 innerFunc의 클로저 덕에 변수 x에 접근 가능

클로저(closure)의 활용


정보의 은닉

의도치 않은 변경을 방지하도록 상태를 은닉하고, 특정 함수에게만 변경을 허용

< 예시 >

let num = 0;

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

console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3
더보기

☝ 위 코드는 num 변수 값이 increase()의 호출전까지 계속 유지되어야하고, 이를 increase()만이 변경가능해야 적절하게 동작

 

❗ 하지만(but)!! 전역적으로 선언했으므로 아무 함수에서나 변경될 우려가 있어 의도치 않은 상태 변경이 예상

< 클로저 사용 예시 >

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

console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3
더보기

✅ 클로저 사용을 통해 num을 함수 스코프 안으로 넣어 은닉하고, increase() 호출 시에만 변경 가능하게 하여 단점을 제거


상태 유지

현재 상태를 기억하고 변경된 최신 상태를 유지

< 예시 >

 // html
 <div class="box" style="width: 100px; height: 100px;
 background: red;"></div>
 
 // js
 const box = document.querySelector('.box');
    const toggleBtn = document.querySelector('.toggle');

    const toggle = (function () {
      const isShow = false;

      return function () {
        box.style.display = isShow ? 'block' : 'none';
        isShow = !isShow;
      };
    })();

toggleBtn.addEventListener('click', toggle);
더보기

✅ 클로저를 사용한 위 코드는 toggle함수가 isShow의 상태를 기억하면서(클로저) 박스의 스타일값을 클릭 이벤트을 통해 변경