클로저를 활용한 예제

seunghw·2022년 11월 6일
0
post-thumbnail

☘️ 클로저를 활용한 예제들을 가져와서 살펴보는 시간을 가지려고 한다. 클로저의 개념에 대해서는
이전에 모듈패턴과 함께 포스팅한 글이 있으므로 정의 정도만 하고 빠르게 본론!

클로저란?

클로저란 함수와 해당 함수가 선언된 렉시컬 환경의 조합이다.
외부 함수가 반환된 후에도 외부 함수의 변수 범위 체인에 접근할 수 있는 함수이다. 전역 변수의 사용을 억제하고, 정보를 은닉하기 위해 사용한다.

비밀번호

이렇게 외부 범위의 변수에 대한 비공개 참조를 유지하게 하는 것이다.
이와 같이 작성한다면 guessPassword함수가 password 변수에 대한 독점적인 엑세스 권한을 갖게 되며
외부로부터 비밀번호에 액세스하는 것을 불가능하게 만든다.

function secretPassword() {
  var password = '123456';
  return {
    guessPassword: function(guess) {
      if (guess === password) {
        return true;
      } else {
        return false;
      }
    }
  }
}

var passwordGame = secretPassword();
passwordGame.guessPassword('777777'); // false
passwordGame.guessPassword('123456'); // true

init() 한번만 실행되게하기

이처럼 data 연결을 한번만 초기화되게 할 수 있다.
간단한 조건문으로 init 함수가 true 이면 코드가 초기화가 되었으며 경고를 콘솔에 기록한다.
initailized가 false인 경우 9,10행이 실행되어 초기화된 변수를 true로 설정하고 콘솔을 반환한다.

14번 라인에서는 initialize 변수를 설정할 때 1번 줄의 init 함수에서 반환되는 4번 줄부터 11번 줄까지 함수가 같기 때문에 클로저다.
즉, 외부함수에서 반환되는 내부함수를 가지고 있으며, 이 내부 함수는 외부함수에서 16-18행에서 내부 함수가 호출될 때 더 이상 존재하지 않을 외부 함수의 변수를 참조합니다.

const init = () => {
  let initialized = false;

  return () => {
    if (initialized) {
      return console.warn('❗️ init function already called, not initializing');
    }

    initialized = true;
    return console.info('initialized 🚀');
  };
};

const initialize = init();

initialize();
initialize();
initialize();
initialized 🚀
❗️ init function already called, not initializing
❗️ init function already called, not initializing

버튼들로 페이지 글자 크기 조정하기

클로저는 데이터와 그 데이터를 조작하는 함수들을 연관시켜주기 때문에 유용하다.
쉽게 말해서 하나의 메소드를 가지고 있는 객체를 일반적으로 사용하는 모든 곳에 클로저를 사용할 수 있다.
js에서 우리가 쓰는 많은 코드들은 이벤트 기반인데 몇 가지 동작을 정의하고 사용자의 이벤트(클릭, 키 누르기)에 연결한다. 이 코드는 대체적으로 콜백이며 이벤트에 응답하여 실행되는 단일함수이다.

예를 들면 들면 페이지 글자 크기를 조정하는 몇 개의 버튼 추가하기가 있다.

    function makeSizer(size) {
      return function() {
        document.body.style.fontSize = size + 'px';
      };
    }

    var size12 = makeSizer(12);
    var size14 = makeSizer(14);
    var size16 = makeSizer(16);

size12,size13,size14는 body 요소의 글자 크기를 각각의 픽셀로 바꾼다. 이 함수들을 연결할 수 있다.

    document<.getElementById('size-12').onclick = size12;
    document.getElementById('size-14').onclick = size14;
    document.getElementById('size-16').onclick = size16;

    <a href="#" id="size-12">12</a>
    <a href="#" id="size-14">14</a>
    <a href="#" id="size-16">16</a>

효율적인 메모리 사용

숫자 배열이 한 번만 생성되도록 클로저를 사용하도록 함수를 만들었다.
17-20행에서 find 함수를 호출하면 find 함수를 몇 번이나 호출해도 배열이 다시 생성되지 않는다.

이것은 클로저를 활용했기 때문이다. 3행의 외부 함수에 정의된 변수를 참조하는 내부 함수가 6행에 있고 내부 함수가 17-20행의 전역 범위에서
호출될 때 외부 함수가 없기 때문에 클로저가 있다. 더 이상 존재하지만 내부 함수는 여전히 외부 함수에 정의된 숫자 변수에 액세스할 수 있다.

const findByIndex = () => {
  console.time('array creation');
  const numbers = Array.from(Array(1000000).keys()); // 숫자배열 생성
  console.timeEnd('array creation');

  return (index) => { // 내부함수 반환, 지정된 인덱스의 숫자 배열에서 항목 가져오기
    const result = numbers[index];

    console.log(`item by index ${index}=${result}`);

    return result;
  };
};

const find = findByIndex();//내부 함수와 동일한 find 함수 생성, 함수가 생성되면 숫자 배열이 생성

find(110351);//3번 호출했음에도 배열생성은 한번.
find(911234);
find(520109);
find(398);
array creation: 52.937ms
item by index 110351=110351
item by index 911234=911234
item by index 520109=520109
item by index 398=398

javadcript 클로저에 대한 7가지 인터뷰 질문

직접 가서 해보면 생각보다 새롭고 어렵다..
https://dmitripavlutin.com/javascript-closures-interview-questions/#questions-5-right-or-wrong-message

참고문헌

https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures
https://dmitripavlutin.com/simple-explanation-of-javascript-closures/

profile
Lumos

0개의 댓글