프로그래밍 패러다임

클래스 안에서 메서드 사용

mount 안에서 render()를 사용할 때 this를 써줘야 한다.
스코프에 의해 그냥 사용할 수 있을 줄 알았는데 왜 그런지 궁금해졌다.
render 함수가 객체 안에 있기 때문에 render는 인스턴스 메소드이다.
인스턴스 메소드는 this를 써야지만 접근이 가능하기 때문에 this를 사용해서 접근해야 한다.

브라우저 엄격모드?

CounterButton 클래스에서 #element는 프라이빗으로 되어 있어 접근이 불가능 해야 하는데
크롬 개발자 모드에선 접근이 가능하다
그래서 vscode 내에서 로그를 찍어봤다. 로그에서 찍었을 땐 구문에러가 발생했다,
왜 그런지 알아봤더니 브라우저는 호환성을 중요시 하기 때문에 이런 현상들을 허용해주는 것이었다.
정리해서 말하자면 크롬은 엄격모드가 아니기 때문에(느슨한 모드) 접근이 가능했던 것이었다.

웹 컴포넌트(Web Components) API


업로드중..

⬇️ ⬇️ ⬇️
class CounterButtonComponent extends HTMLElement {
  #config = {
    count: 0,
    step: 1,
  };

  constructor() {
    super();
    this.#init();
  }

  #init() {
    const userConfig = {
      count: Number(this.getAttribute("count")),
      step: Number(this.getAttribute("step")) || 1,
    };

    this.#config = { ...this.#config, ...userConfig };
  }

  // 버튼 클릭 이벤트를 처리하고, 카운트 값을 증가시키고 컴포넌트를 다시 렌더링하며, update 이벤트를 발생시킵니다
  /* 
   dispatchEvent()를 사용하여 "update"라는 이름의 커스텀 이벤트를 발생시키고, this.#config.count 값을 이벤트의 detail 속성에 전달
   "update" 이벤트를 리스닝하는 다른 요소에서 해당 값을 사용하여 UI나 상태를 업데이트 할 수 있음
  */
  #bindEvent(e) {
    if (e.target.matches("button")) {
      this.#setCount();
      this.render();
      // 참고: https://developer.mozilla.org/ko/docs/Web/Events/Creating_and_triggering_events
      this.dispatchEvent( //  DOM 요소에 이벤트를 발생시키기 위해 사용되는 메서드
        new CustomEvent("update", { detail: this.#config.count }) // (update라는 이름의 커스텀 이벤트를 생성 , 이벤트에 전달할 추가 정보를 담고 있는 객체 { detail: ... } 형태로 전달)
      );
    }
  }

  #setCount() {
    const { count, step } = this.#config;
    this.#config.count = count + step;
  }

  connectedCallback() { // 컴포넌트가 DOM에 연결될 때 호출되는 메서드로, 초기 렌더링을 수행하고 클릭 이벤트를 등록
    // console.log('connected');
    this.render();
    this.addEventListener("click", (e) => this.#bindEvent(e));
  }

  disconnectedCallback() { // 컴포넌트가 DOM에서 연결이 끊어질 때 호출되는 메서드로, 클릭 이벤트를 제거
    // console.log('disconnected');
    this.removeEventListener("click", (e) => this.#bindEvent(e));
  }

  render() {
    const { count } = this.#config;
    this.innerHTML = `<button type="button">${count}</button>`;
  }
}

customElements.define("counter-button", CounterButtonComponent);
const counterButtonEl = document.querySelector("counter-button");
/* 
counterButtonEl.addEventListener("update", ...): counter-button 요소에 대한 update 이벤트를 처리합니다. 
해당 이벤트가 발생하면 카운트 값이 변경된 내용을 .web-component 클래스를 가진 요소의 텍스트로 업데이트합니다.

이 코드를 실행하면 <counter-button> 요소가 등록되어 웹 컴포넌트로 사용됩니다. 이 버튼을 클릭하면 카운트 값이 증가하며, update 이벤트가 발생하여 다른 요소의 텍스트가 업데이트됩니다.
*/
counterButtonEl.addEventListener("update", (e) => { // update -> 사용자 정의 이벤트 사용
  document.querySelector('.web-component').textContent = String(e.detail);
});

함수형 프로그래밍

상태(state)와 변경 가능성(mutable)을 최소화하고, 대신 함수의 조합으로 복잡한 로직을 해결

📌 함수형 프로그래밍 기본 원칙


  • 함수는 하나 이상의 기능을 제공할 수 있습니다.
  • 하지만 FP에서 함수는 단 하나의 기능에 집중합니다.
  • 변하지 않는 변수에 대한 함수를 작성합니다.
const dummyDocument = {
  body: {
    innerHTML: "",
  },
};

// ----------------------------------------
// 함수는 하나 이상의 기능을 제공할 수 있습니다.
// - 일반적으로 함수를 작성할 때 여러 일을 처리하도록 구성합니다.

function fetchAndRenderAndLogAlbumList() {
  fetch("https://jsonplaceholder.typicode.com/album/1/photos?_start=0&_limit=4")
    .then((response) => response.json())
    .then((data) => {
      dummyDocument.body.innerHTML = `
        <ul class="albumList">
          ${data
            .map(
              ({ albumId, id, title, url, thumbnailUrl }) =>
                `
                <li class="albumItem">
                  <a class="albumLink" href="${url}">
                    <img class="albumThumbnail" src="${thumbnailUrl}" alt="" />
                    <div role="group" class="albumInfo">
                      <strong class="albumTitle">${title}</strong>
                      <span class="albumId">${albumId}</span>
                    </div>
                  </a>
                </li>
              `
            )
            .join("")}
        </ul>
      `;

      console.log(dummyDocument.body.innerHTML);
    })
    .catch((error) => console.error(error.message));
}

fetchAndRenderAndLogAlbumList();

한 함수의 여러가지 기능이 있는 함수를 분리해보았다.

function fetchData(endpoint) {
  return fetch(endpoint)
    .then((response) => response.json())
    .catch((error) => console.error(error.message));
}

function renderAlbumList(data, container) {
 container.innerHTML = `
  <ul class="albumList">
    ${data
      .map(
        ({ albumId, id, title, url, thumbnailUrl }) =>
          `
          <li class="albumItem">
            <a class="albumLink" href="${url}">
              <img class="albumThumbnail" src="${thumbnailUrl}" alt="" />
              <div role="group" class="albumInfo">
                <strong class="albumTitle">${title}</strong>
                <span class="albumId">${albumId}</span>
              </div>
            </a>
          </li>
        `
      )
      .join("")}
  </ul>
`;
return container
}

function log(container) {
  console.log(container.outerHTML);
}

async function run() {
  // 데이터 패치(가져오기)
  const responseData = await fetchData(
    "https://jsonplaceholder.typicode.com/album/1/photos?_start=0&_limit=4"
  );
  // 데이터 기반 렌더링
  const container = renderAlbumList(responseData, document.querySelector('#demo')); 
  // 로그
  log(container)
}

run();
profile
진주링딩동🎵

0개의 댓글