[DAY 13] VanillaJS를 통한 자바스크립트 기본 역량 강화 I (2)

송히·2023년 10월 5일
post-thumbnail

Today I Learn📖

  • 명령형 프로그래밍 방식 (강의)
  • 선언적 프로그래밍 방식 (강의)
  • 이벤트 버블링, 이벤트 리스너, e.target (추가 학습)
  • function과 new의 관계 (추가 학습)

명령형 프로그래밍, 선언적 프로그래밍

  • 명령형(절차적) 프로그래밍: 컴퓨터가 수행할 명령들을 순서대로 써 놓은 것
    -> 구현 방법을 상세하고 디테일하게 기술하는 것에 초점을 둠 (방법)

  • 선언적(함수형) 프로그래밍: 나타내야할 목표를 명시하고 알고리즘은 명시하지 않는 것
    ex) HTML (그려야 하는 것을 코드로 나타냄(목표), 뒤에서 복잡하게 그려지는 동작 과정은 따로 생각하지 않음(방법 X))


배열 요소들에 2를 곱하는 함수를 나타낸 위 2가지 코드를 보면 차이점을 알 수 있다.

  • 명령형 프로그래밍: 결과 배열 선언, for문으로 하나하나 방법을 나타냄
  • 선언형 프로그래밍: map함수를 사용해 현재 배열을 이용해 새 배열 만들 것을 명시, n => n * 2를 이용해 원하는 목적을 명시 (사용자가 목적 이해를 빨리 할 수 있음)

선언적 프로그래밍을 사용해야 하는 이유

  • 명령형 프로그래밍은 조건이 생기면 하나하나 적어야함 -> 양파처럼 계속 큰 함수 안에 쌓임
    => 많아지면 복잡해져서 이해하기 힘들고 읽기도 힘듦, 규칙성 없이 적어두면 유지보수 힘듦

  • 선언적 프로그래밍은 사용 목적이 분명한 메서드를 사용해 무엇을 할 것인지 설명
    -> 새로운 요구사항이 생겨도, 그 요구사항을 이행하기 위한 사고방식의 흐름대로 표현 가능
    => 메서드 만으로 목적 이해 가능, 코드도 간결해져서 읽기 쉬움

const data = [
  {
    name: "송희",
    job: "학생",
    age: 25,
  },
  {
    name: "원필",
    job: "가수",
    age: 30,
  },
  {
    name: "도운",
    job: "가수",
    age: 29,
  },
  null,
];

/* "person 객체가 제대로 들어있음, 직업이 가수임, 나이가 30대 이상임"의 조건을 만족하는 사람 찾기
*/

// 명령형 프로그래밍
function filterOlderSinger(persons, maxAge) {
  let result = [];

  for (let i = 0; i < persons.length; i++) {
    const person = persons[i];

    if (person && person.job == "가수" && person.age > maxAge) { // 조건 길게 나열됨, 또 추가 사항 생기면 양파처럼 for문 안에 또 생기게 될 것.,,
      result.push(person.name);
    }
  }

  return result;
}

console.log(filterOlderSinger(data, 29)); // ["원필"]

// 선언적 프로그래밍
function filterOlderSinger(persons, maxAge) {
  return persons.filter((person) => person && person.job == "가수" && person.age > maxAge) // 필터 메서드로 조건 거르기
    .map((person) => person.name); // map 메서드와 그 내용으로 새 배열 반환
}

console.log(filterOlderSinger(data, 29)); // ["원필"]

.filter(): 배열 요소들을 돌며 true만 넘겨줌


기능 구현시 명령형과 함수형의 차이

  • 명령형 프로그래밍 방법: 같은 역할이지만 대상이 다르면 노가다로 반복해서 써야함.,,
    담당 영역도 정해져있고, 명령 순서에 의존해서 동작하기 때문에 기능 추가 유지보수 어려움
    코드가 길어지고 복잡해지고 더러워져서 알아보기 힘듦
    -> 버그 발생 가능성 상승, 예상치 못한 결과 발생 가능

  • 선언적 프로그래밍 방법: 기능 담당 함수 만들어서 재사용 가능, 코드 읽기 쉬움
    -> 더 나아가 추상화까지 가능

추상화

  • 추상화: 컴포넌트 방식의 추상화 (각 역할에 필요한 기능들을 한곳에 모아두는 것)
    => 각 기능의 역할이 잘 보이고 순서도 잘 보임
    -> 기능 추가, 유지보수 용이성 높음

  • 공통적인 역할은 함수로 만들고 new 키워드 사용해서 여러 개 생성 가능
    -> 그 중 하나에만 쓰고 싶은 기능은 해당 new 객체에 함수로 정의
    (해당 객체에 함수를 정의하기 때문에, 여러 객체에서 함수 이름이 같아도 내용은 각각 다름 -> 비슷한 기능 하는 함수 생성 가능 (확장 가능))

function onePart({ $target, text, onClick }) {
  const $button = document.createElement("button");
  $target.appendChild($button);

  let clickCount = 0;

  this.render = () => {
    $button.textContext = text;
  };

  $button.addEventListener("click", () => {
    /* ~기본 클릭 기능~*/

    if (onClick) {       // 버튼 1, 2에만 적용하고 싶은 기능 (각각 내용은 다름)
      onClick(clickCount); // 정의된 onClick 함수에 매개변수로 clickCount 넘김
    }
  });
}

new onePart({
  // 버튼 1 생성
  $target: $app,
  text: "버튼 1",
  onClick: (clickCount) => { // onePart의 clickCount 받아와서 매개변수로 사용
    /* onClick 기능 1 */
  },
});

new onePart({
  // 버튼 2 생성
  $target: $app,
  text: "버튼 2",
  onClick: (clickCount) => {
    /* onClick 기능 2 */
  },
});

new onePart({
  // 버튼 3 생성
  $target: $app,
  text: "버튼 3",
});
  • 상태 관리 방법: state를 통해 추상화 후, 상태를 기반으로 렌더링 (DOM 접근 최소화)
function onePart({ $target, text, onClick }) {
	...
    
  this.state = { // 상태들 저장
    clickCount: 0,
    toggled: false,
  };

  this.setState = (nextState) => { // 저장된 상태들을 다음에 올 nextState로 바꿈
    this.state = nextState;
    this.render(); // 아래 render함수 정의해서 렌더링
  };

  this.render = () => { // 상태를 기준으로 동작
    /* this.state.clickCount 혹은 this.state.toggled의 값 활용한 기능 */
  };

  $button.addEventListener("click", () => {
    this.setState({ // 상태 업데이트 -> nextState 됨
      clickCount: this.state.clickCount++,
      toggled: !this.state.toggled,
    });
  });
}
  • 그룹화: 같은 기능의 객체 여러 개 생성시 묶어두는 것
    -> 재사용성 올라감, 독립적임(외부의 값 영향 없음)
function BtnGroup({ $target, buttons }) {
  const $group = document.createElement("div");
  let isInit = false;

  this.render = () => {
    if (!isInit) { // 최초 버튼일 때
      buttons.forEach(({ type, ...props }) => { // 타입에 따라 호출하는 함수 다름 (다른 기능의 객체 만들어야하니까)
        if (type === "toggle") new ToggleBtn({ $target: $group, text });
        else if (type === "timer") new TimerBtn({ $target: $group, text });
      });

      $target.appendChild($group);
      isInit = true;
    }
  };
}

new BtnGroup({ // 버튼들 그룹화 (공통된 건 위에, 다른 세부적인 내용은 각각)
  $target: $app,
  buttons: [
    {
      type: "toggle",
      text: "토글 버튼 1",
    },
    {
      type: "toggle",
      text: "토글 버튼 2",
    },
    {
      type: "timer",
      text: "타이머 버튼",
    },
  ],
});
  • document.createElement(): JavaScript에서 DOM(Document Object Model)을 사용하여 새로운 HTML 요소를 생성하는 메서드
  • document.queryselector(): 웹 페이지의 HTML 문서에서 특정 CSS 선택자에 일치하는 첫 번째 요소를 JavaScript로 선택하는 메서드
    -> 원하는 요소를 찾아내서 해당 요소에 대한 조작 가능
  • 부모요소.appendChild(자식요소): 요소를 부모 요소의 자식으로 추가하는 메서드
  • timer에서 1000 = 1초
  • 파라미터(변수) 이름 앞에 접두사 on: '뒤 행위를 할 때 실행하는 것' 이라는 뜻 ex) onClick

이벤트 기능

  • 이벤트: 웹 페이지에서 발생하는 사용자 액션 또는 브라우저 자체에서 일어나는 사건 (클릭, 키패드 누름, 마우스 움직임 등의 상호작용)

  • 이벤트 버블링: 웹 페이지의 DOM에서 이벤트가 발생한 하위 요소에서 상위 요소로 이벤트가 전파되는 현상
    => 이벤트가 전파되면서 각 요소에서 등록된 이벤트 핸들러가 호출됨
    (<-> 이벤트 캡처링: 상위 요소에서 하위 요소로 전파됨)

  • .addEventListener("이벤트 종류", 이벤트 발생시 실행될 함수): 이벤트 핸들러를 등록하는 메서드
    => 이벤트 발생시 실행될 함수의 인자에는 관례적으로 event의 e를 넣음

  • e.target: target 속성은 이벤트가 발생한 대상을 가리킴
    => 구조 분해 할당(구조 분해 문법)을 사용하면 가독성 좋아짐
    const { target } = e; (이벤트 객체 e에서 target 속성만 추출해 새로운 변수 target에 할당하여 사용)

/* 위, 아래는 같은 이벤트의 타겟을 가리킴 */

// 기본 문법
e.target.함수~

// 구조 분해 할당
const { target } = e;
target.함수~

function과 new의 관계

  • functionnew는 JavaScript에서 객체 지향 프로그래밍의 객체 생성에 관계있음

  • function: 생성자 함수 정의 (객체를 생성함, this 사용)

  • new: 생성자 함수를 호출하여 새로운 객체를 생성하는 데 사용됨 (생성자 함수의 this가 해당 객체를 가리킴 -> 거기에 매개변수 속성 할당)


😊오늘의 느낀점😊

명령형 프로그래밍처럼 방식을 디테일하게 구현한 메서드들이 존재하고, 그 메서드들을 잘 사용해서 목적을 이해하기 쉽게 표현하는 것이 선언적 프로그래밍이라고 이해했다.

특히 강사님의 명령형 프로그래밍은 양파같아진다 라는 말씀이 너무 귀여워서 인상깊게 남았다.

필요한 것을 만들기 위해 사고를 분할시키고, 그에 맞는 메서드를 사용하는 선언형 프로그래밍 방식을 사용하도록 노력해야겠다.

출처: 이벤트 버블링 그리고 e.target, e.currentTarget 기초 정리

profile
데브코스 프론트엔드 5기

0개의 댓글