티스토리 뷰

카테고리 없음

클로저(과제)

개춘기뽀삐 2024. 9. 19. 21:09

▶️ 클로저란 무엇인가요?

클로저의 개념뿐 아니라, 클로저가 실제로 어떻게 사용될 수 있는지 구체적인 예시도 같이 설명해주세요. 그리고 클로저의 장단점에 대해서도 같이 작성해주세요.

클로저는 렉시컬 환경의 조합으로 스코프 체인을 통해 이뤄집니다.

전역 변수를 지역변수화 시켜 내부 함수에서만 참조할 수 있도록 해 전역 스코프로 인한 오류를 방지하는 기술로 데이터 은닉과 캡슐화를 사용할 수 있습니다.

클로저의 장점

  • 데이터 은닉을 통해 외부 접근으로 인한 의도치 않은 변경을 막을 수 있습니다
  • 함수 호출 이후에도 가비지 컬렉터에 의해 수집되지 않아 데이터의 상태를 기억시킬 수 있습니다

클로저의 단점

  • 함수가 가비지 컬렉션에서 제외되어 메모리에 계속 남아있기 때문에 메모리 누수가 발생할 수 있습니다

클로저를 통해 할 수 있는 것

  1. 특정 계산을 위한 함수 또는 카운터를 위한 함수
  • 데이터 은닉으로 계산식 또는 카운터에 의도치 않은 변경을 막을 수 있기 때문에 클로저를 사용하는 것이 유용합니다.
function closure() {
  let cnt = 0; 

  // cnt 증가 함수 
  function cntPlus() {
   console.log(cnt++); 
  }
  
  // cnt에 인자를 전달해 값 변경하는 함수
  function setCnt(val) {
    console.log( cnt = val); 
  }
  
  return { cntPlus, setCnt, printCnt };
}

const cntClosure = closure();
cntClosure.cntPlus(); 
cntClosure.setCnt(100); 
  1. 객체 생성을 위한 사용
  • printIntroduction함수로 반환된 createIntroduction의 매개변수는 가비지컬렉션에서 제외되기 때문에 상태를 유지할 수 있습니다 이로 인해 클래스와 생성자 함수 없이 간단하게 객체처럼 사용할 수 있습니다.
function createIntroduction(name,age) {

function printIntroduction(){
  console.log(`제 이름은 ${name}입니다 ${age}살 입니다.`);
}

return printIntroduction

}
createIntroduction("김뽀삐",8)

▶️ 다음 코드를 읽고 결과를 설명해주세요.

var datepopCounter = (function() {
  var privateCounter = 0;
  
  function changeBy(val) {
    privateCounter += val;
  }
  
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    },
  };
})();

console.log(datepopCounter.value());

datepopCounter.increment();
datepopCounter.increment();

console.log(datepopCounter.value());

datepopCounter.decrement();
console.log(datepopCounter.value());

코드 해석

  1. datepopCounter 함수는 즉시 실행 함수로 정의와 동시 실행되는 함수입니다.
  2. datepopCounter 함수 내부에는 privateCounter 변수와 changeBy 함수가 있습니다.
  3. changeBy 함수는 privateCounter 변수의 값을 변경하는 함수입니다.
  4. datepopCounter 함수의 반환값은 객체 형태로 increment, decrement 메서드를 통해 changeBy 함수를 호출하고 privateCounter 변수 값을 조작합니다 value메서드로 privateCounter 변수를 반환합니다.
  5. 결론적으로 클로저를 이용해 외부에서 접근할수 없는 privateCounter 변수를 변경하고 상태를 저장하는 로직입니다.

결과

  • 첫 번째 콘솔은 datepopCounter 함수의 privateCounter 변수를 출력하기 때문에 (0)이 출력됩니다
  • 두 번째 콘솔은 datepopCounter.increment(); 이 두 번 호출되었기 때문에 1씩 증가하여 (2)가 출력됩니다
  • 세 번째 콘솔은 위에서 +2를 해주었기 때문에 1을 뺀 (1)이 출력됩니다

▶️ 다음 코드를 읽고 결과를 설명해주세요.

코드에 문제가 있다면 어떻게 개선하면 좋을지 제안해주세요

function datepopPopdeal(amount) {
  var defaultDisCountRate = 0.3

  return {
    price: function () {
      return (1 - defaultDisCountRate) * amount;
    }
  }
}

let popdeal = datepopPopdeal(10000);
console.log("할인된 가격은 " + popdeal.price());
console.log("원래 가격은 " + popdeal.amount); 
  1. popdeal 변수를 통해 datepopPopdeal 함수에 인자를 전달합니다
  2. 첫 번째 콘솔은 datepopPopdeal 함수의 반환 객체를 통해 amount으로 계산을 합니다**(1 - 0.3) * 10000 = 7000**
  3. 두 번째 콘솔은 amount값을 출력하고있지만 datepopPopdeal 함수의 반환 객체에 속하지않기 때문에 **undefined**으로 출력됩니다

개선된 코드

function datepopPopdeal(amount) {
  var defaultDisCountRate = 0.3;

  return {
    price: function () {
      return (1 - defaultDisCountRate) * amount;
    },
    print: amount,
  };
}

let popdeal = datepopPopdeal(10000);
console.log("할인된 가격은 " + popdeal.price());
console.log("원래 가격은 " + popdeal.print);

▶️ 아래 코드를 실행할 경우, 발생할 수 있는 문제를 설명해주세요.

이를 해결하기 위한 방법도 제안해주세요. 추가로, 코드가 더 효율적으로 동작하도록 개선할 방법도 함께 설명해주세요.

function popUIButton(elements) {
  for (let i = 0; i < elements.length; i++) {
   elements[i].addEventListener("click", function() {
      console.log(`지금 누른 버튼은 ${i}번째 입니다!`);
    }); 
  }
}

코드 해석

  1. popUIButton 함수는 버튼을 인자로 받고 있고 내부에 반복문이 있습니다 i의 최초값은 0이고, i는 elements길이보다 작고, i는 반복한다 는 조건을 가지고 있습니다.
  2. 각 버튼에 addEventListener로 클릭 이벤트를 주입하고 버튼을 클릭할 경우 해당 버튼의 인덱스를 출력하는 로직입니다

발생할 수 있는 문제

  1. 인자로 받고 있는 버튼이 배열 형태가 아니거나, 배열이 비어있는 경우 오류가 발생할 수 있습니다
  2. 버튼의 개수가 많을 경우, 모든 버튼에 addEventListener를 등록하면 성능 저하의 원인이 될 수 있습니다.

개선된 코드

document
  .getElementById("container")
  .addEventListener("click", function (event) {
    if (event.target && event.target.matches(".button")) {
      const btns = Array.from(document.querySelectorAll(".button")).indexOf(
        event.target
      );
      console.log(`지금 누른 버튼은 ${btns}번째 입니다!`);
    }
  });
  • 이벤트 델리게이션 패턴을 이용해 클릭한 대상에만 이벤트를 적용할 수 있도록 부모 요소에 addEventListener를 적용합니다
  • 조건문을 이용해 이벤트 대상이 있고, 대상의 클래스명이 일치할 경우에만 접근이 가능합니다
  • 동일한 클래스명을 가진 버튼 요소를 Array.from으로 배열로 변환하고 메서드 체이닝으로 indexOf를 이용해 클릭한 버튼의 인덱스를 추적합니다(querySelectorAll는 NodeList로 유사배열이지만 indexOf 사용을 위해 배열로 인식할 수 있도록 변환해줍니다.)
  • 결국 btns 변수에는 클릭한 버튼의 인덱스가 할당됩니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함