Skip to content

Conversation

@Tutankhannun
Copy link

@Tutankhannun Tutankhannun commented Sep 13, 2025

배포링크

Review Question

1. DOM은 무엇인가요?

DOM(Document Object Model): 브라우저가 HTML 문서를 트리 구조의 객체 그래프로 표현한 모델
각 태그(요소)는 **노드(node)**가 되고, JS로 이 노드들을 찾고/만들고/지우고/속성을 바꿀 수 있다.
image

이번 코드를 짜면서 다음과 같이 사용됐다.

찾기: document.getElementById('todoList'), querySelector('.list-section')
생성: document.createElement('li')
수정: el.textContent = '…', el.className = 'todo-item done'
삽입/삭제: parent.appendChild(li), el.remove(), listEl.innerHTML = ""

listEl.innerHTML = "";              // 1) 기존 li 다 지움
filtered.forEach(t => {             // 2) JS 상태(todos) → li DOM 생성
  const li = document.createElement('li');
  li.className = 'todo-item' + (t.done ? ' done' : '');
  li.dataset.id = t.id;
  li.innerHTML = `
    <span class="title">${escapeHtml(t.text)}</span>
    <div class="actions"> … </div>
  `;
  listEl.appendChild(li);           // 3) DOM 트리에 삽입
});`

2. 이벤트 흐름 제어(버블링 & 캡처링)이 무엇인가요?

이벤트 흐름 제어캡처링 → 타겟 → 버블링 의 3단계 흐름을 가진다.

  1. 캡처링(capturing): window → document → html → body → … → 타깃 (위에서 아래로)
  2. 타깃(target): 실제로 이벤트가 발생한 그 요소에서 핸들러 실행
  3. 버블링(bubbling): 타깃 → … → body → html → document → window (아래에서 위로)

과제에서 다음과 같이 적용되었다.

listEl.addEventListener('click', (e) => {
  const li = e.target.closest('.todo-item'); // 타깃에서 시작해 상위로
  if (!li) return;
  const btn = e.target.closest('[data-action]');
  if (!btn) return;

  if (btn.dataset.action === 'delete') {
    // 삭제 로직
  }
});

listEl.addEventListener('change', (e) => {
  const input = e.target.closest('input[type="checkbox"][data-action="toggle"]');
  if (!input) return;
  const li = input.closest('.todo-item');
  // 완료 토글 로직
});

매 항목마다 리스너를 달지 않고, 부모 하나에만 달아 버블링으로 처리했다.
e.target은 실제 클릭된 가장 깊은 요소로 closest()을 통해 역할(버튼/체크박스/리스트 아이템)을 찾아 올라감.

3. 클로저와 스코프가 무엇인가요?

클로저(Closure): 함수 + 그 함수가 선언될 때의 스코프(환경)가 함께 저장되는 현상
->바깥 함수의 변수를 내부 함수가 기억하고 접근할 수 있게 한다.
상태가 의도치 않게 변경되지 않도록 상태를 안전하게 은닉하고 특정 함수에게만 상태 변경을 허용하기 위해 사용한다.

스코프(Scope): 변수에 접근 가능한 범위
1.전역 스코프(global)는 어디에서든 해당 변수에 접근 가능
2.지역 스코프(local)의 경우, 한정적인 범위에서 해당 변수에 접근이 가능(JS는 지역 스코프의 두 가지 유형 지원)

  • 함수 스코프: function 내부에서 선언한 것은 그 함수 안에서만 접근 가능
  • 블록 스코프: let/const는 {} 블록 안에 묶이면 블록 내부에서만 접근 가능 (if, for 등)
image

<참고자료>
DOM이란
스코프

Copy link

@only1Ksy only1Ksy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 윤성 님! 1주차 과제 진행하시느라 고생 많으셨습니다 👍 전반적으로 구조가 깔끔하게 작성되어 이해하기 편했고, 특히 이번 과제의 KQ를 잘 반영해 코드에 녹여내신 부분이 인상적이었습니다! 몇 가지 리뷰를 남겨 보았으니 참고해 보시면 좋을 것 같습니다 ☺️

const datePicker = document.getElementById("datePicker");
const todayEl = document.getElementById("todayLabel");

const form = document.getElementById("todoForm");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 Id를 가지고 있는 요소가 없는 것으로 보입니다!

@@ -0,0 +1,201 @@
// 유틸

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

유틸 함수가 상단에 잘 분리되어 있어 가독성이 좋은 것 같습니다👍

});
}

// 리스트 이벤트 위임

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번 KQ였던 이벤트 흐름 제어를 잘 적용해 주셨네요!!

render();

// 추가
if (form) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 마찬가지로 form 요소가 없어 아래 else if 문으로만 분기처리 되고 있는 것 같습니다!

Comment on lines 124 to 125
input.addEventListener("keydown", (e) => {
if (e.key === "Enter") addFromInput();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
input.addEventListener("keydown", (e) => {
if (e.key === "Enter") addFromInput();
input.addEventListener("keydown", (e) => {
if (e.isComposing) return;
if (e.key === "Enter") addFromInput();

keydown 이벤트를 활용할 때, enter를 누르면 한글 중복 입력 문제가 발생할 수 있습니다! isComposing 을 활용하면 이를 방지할 수 있으니 참고해 주시면 좋을 것 같습니당

due: currentDate,
});
save();
render();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지금은 리스트가 하나 추가될 때마다 render()를 호출해 전체 요소를 리렌더링 하고 있는 것으로 보이는데, 새로 추가된 요소만 appendChild로 붙여 주는 방식으로 개선하면 불필요한 DOM 재생성을 줄일 수 있어 성능 측면에서 더 효율적일 것 같습니다! 삭제나 토글 로직도 같은 측면에서 개선의 여지가 있어 보입니당

listEl.appendChild(li);
});
const items = listEl.querySelectorAll(".todo-item");
if (items.length > 5) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

딱 리스트가 다섯 개만 보이도록 높이를 동적으로 계산해 주신 부분이 디테일하네요!!👍
다만 해당 부분은 render 함수 안에 포함시키기보다는 별도의 함수로 분리하는 방식도 고려해 보시면 좋을 것 같습니당

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants