Skip to content

[1주차] 김홍엽 과제 제출합니다.#4

Open
Yeobi00 wants to merge 7 commits intoCEOS-Developers:masterfrom
Yeobi00:yeobi00
Open

[1주차] 김홍엽 과제 제출합니다.#4
Yeobi00 wants to merge 7 commits intoCEOS-Developers:masterfrom
Yeobi00:yeobi00

Conversation

@Yeobi00
Copy link
Copy Markdown

@Yeobi00 Yeobi00 commented Mar 14, 2026

배운 점

1. DOM 조작

  • document.createElement, appendChild를 활용해 HTML 요소 동적으로 생성하고 DOM 트리에 추가할 수 있다.

2. JSON 직렬화/역직렬화와 객체 기반 데이터 관리

  • localStorage에는 문자열만 저장할 수 있기 때문에, JSON.stringify()JSON.parse()를 활용해 객체 형태의 데이터를 저장하고 다시 복원하는 방식으로 사용할 수 있다.

3. Semantic HTML

  • 시맨틱 태그는 div처럼 단순한 구조용 태그와 달리, 태그 자체가 해당 영역의 의미와 역할을 나타내는 HTML 요소를 의미한다.
  • main, header, nav, section, form 등의 시맨틱 태그를 활용해 페이지의 구조를 의미 단위로 명확하게 구분할 수 있다.
  • 코드 가독성을 높이고, 스크린 리더와 검색 엔진이 페이지 구조를 보다 쉽게 파악할 수 있도록 할 수 있다.

4. CSS Flexbox

  • Flexbox는 요소들을 한 방향(가로 or 세로)으로 정렬하고 공간을 효율적으로 배치할 수 있도록 하는 CSS 레이아웃 모델이다.
  • display: flex, flex-direction, gap, flex: 1 등의 속성을 활용해 요소들을 유연하게 정렬하고 간격을 관리할 수 있다.

5. BEM 네이밍

  • block__element--modifier 구조를 사용하여 컴포넌트 단위(Block), 그 내부 요소(Element), 상태(Modifier)를 구분하여 표현할 수 있다.
  • CSS 스타일의 역할과 위치를 쉽게 파악해 스타일 범위를 명확하게 관리할 수 있다.
     

많은 시간을 투자한 부분

주간 네비게이션 날짜 계산

  • JS의 Date 객체에서 제공하는 getDay(), getDate(), setDate() 등의 메서드를 활용해 현재 날짜를 기준으로 해당 주의 시작 날짜(일요일)를 계산하는 로직을 구현했습니다.
  • getDay()는 요일을 숫자 인덱스로 반환하며, 일요일이 0, 월요일이 1로 시작한다는 점을 고려해 주간 날짜 계산 로직에 반영했습니다.
     

배포 링크

🔗 https://ceos-week1-vanilla-todo-23rd-mk2a.vercel.app/
 

Review Questions

1. DOM은 무엇인가요?

  • DOM(Document Object Model)은 HTML 문서 구조를 객체와 노드의 트리 구조로 표현한 모델이다.
  • 브라우저는 HTML을 DOM 구조로 변환해 메모리에 저장하며, JS는 이를 통해 문서의 구조, 내용, 스타일을 동적으로 변경할 수 있다.
  • DOM은 트리 형태로 구성되며, 각 노드는 부모, 자식, 형제 관계를 가진다.
  • HTML은 브라우저의 HTML 파서에 의해 DOM으로 변환되며, 파싱 중 <script> 태그를 만나면 DOM 생성을 일시 중단하고 자바스크립트를 먼저 실행한다.
  • <script> 위치에 따라 DOM 생성이 지연될 수 있으므로, DOM이 먼저 생성될 수 있도록 스크립트는 문서 하단에 배치하는 것이 권장된다.
     

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

  • 브라우저에서 이벤트가 발생하면 DOM 트리를 따라 전파되고, 이벤트 전파에는 버블링(Bubbling)과 캡처링(Capturing) 이라는 두 가지 단계가 존재한다.
  • DOM 이벤트 흐름은 1️⃣ 캡처링 → 2️⃣ 이벤트 처리 → 3️⃣ 버블링 흐름으로 진행된다.
  1. 캡처링: 이벤트가 DOM 트리의 최상위 요소(root)에서 시작해 실제 이벤트가 발생한 요소(target)까지 내려가는 과정
    - Window → Document → html → body → ... → Target Element
    - 이 과정에서 상위 요소들이 타겟 요소보다 먼저 이벤트를 감지할 수 있다.

  2. 버블링: 실제 이벤트가 발생한 요소에서 시작해 DOM 트리를 따라 상위 요소로 올라가는 과정
    - Target Element → Parent Element → ... → Document → Window
    - 대부분의 DOM 이벤트는 버블링 단계에서 처리된다.

  이벤트 흐름을 어떻게 활용 가능할까?

  • 이벤트 위임: 자식 요소 각각에 이벤트 리스너를 등록하는 대신, 공통 부모 요소에 이벤트를 등록하고 버블링을 이용해 처리하는 방식
    • 자식 요소마다 이벤트 리스너를 등록하면 요소가 많아질수록 이벤트 리스너가 증가하는 문제가 있지만, 이벤트 위임을 사용하면 부모 하나에만 이벤트 리스너를 등록해 메모리 사용과 관리 비용을 줄일 수 있다.
    • 부모 요소에 등록된 이벤트는 버블링을 통해 전달되므로, 이후 동적으로 생성된 자식 요소에서도 별도의 이벤트 등록 없이 정상적으로 이벤트를 처리할 수 있다.
       

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

  1. 스코프: 현재 어떤 값이나 표현식에 접근할 수 있는 실행 문맥
    - 어떤 변수나 함수가 어디서부터 어디까지 유효한지, 어디에서 참조할 수 있는지를 결정하는 규칙
    - 스코프는 계층 구조를 가지며, 안쪽 스코프는 바깥쪽 스코프에 접근 가능하지만, 그 반대는 불가능하다.
    - 전역(Global) 스코프, 지역(Local/Function) 스코프, 블록(Block) 스코프로 나뉜다.
    - var는 함수 레벨, let/const는 블록 레벨을 따른다.

  2. 클로저: 주변 상태에 대한 참조와 함께 묶인 함수의 조합
    - 함수가 선언될 당시의 외부 스코프를 기억하고, 이후에도 그 스코프 내의 변수들에 계속 접근할 수 있다.
    - 함수가 자신의 외부 어휘적 환경을 기억하기 때문에 가능하다.

예시

function makeCounter() {
  let count = 0;
      
  return function () {
    count += 1;
    return count;
  };
}
    
const counter = makeCounter();
    
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

Copy link
Copy Markdown

@Wannys26 Wannys26 left a comment

Choose a reason for hiding this comment

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

과제하시느라 고생많으셨습니당!!

다음 과제가 react + tailwind 마이그레이션이기에,
html + css + js 로 구현했을때보다
react와 tailwind가 어떤 점이 더 나은지? 어떤 점이 달라지는지? 를 고민해보셨으면 하는 마음으로 리뷰 달았습니다!

노력이 깃든 코드 볼 수 있어서 좋았습니당 ㅎㅎ

Comment thread style.css
Copy link
Copy Markdown

@Wannys26 Wannys26 Mar 14, 2026

Choose a reason for hiding this comment

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

:root 변수 선언

:root {
  /* color */
  --color-black: #3f454d;
  --color-white: #ffffff;
  --color-yellow: #fbbe28;
}
.item {
  background-color: var(--color-white);
}

:root 를 활용하셔서, 색상, 폰트, shadow 등등 여러가지 값들을 변수 선언(디자인 토큰으로 정의)하시는 걸 추천드립니당!


디자인과 협업을 한다고 생각했을때, 만약
"background-color: #f5f5f7; 해당 색상을 좀 더 밝게 바꿔도 괜찮을까요?" 라고 한다면

:root 에서 정의해둔 값의 hex 코드만 바꾼다면 쉽게 해결이 될 수 있으니까요!

+) 유민님 css 파일 참고하시면 좋을 듯합니당!

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

디자이너의 디자인 토큰 정의
결국 디자이너도 이미 변수값으로 정의해둔 (색상 + 폰트 + ..etc) 등을 조합해서 피그마 디자인을 만들어내기 때문에,
디자이너의 수정 사항 및 여러 변수에 대응하기가 더 쉬워집니당

Comment thread style.css
font-size: 14px;
}

/* Dark Mode */
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

dark모드 관련 코멘트도 위의 :root 정의랑 이어지는 이야기입니다!

만약 구현하셔야 되는 내용이 하나의 페이지가 아니라,
여러개의 페이지에 전부 dark모드가 일괄 적용 되어야 한다면,
변수로 지정해두시는게 dark 모드 대응이 수월할 것입니당!


다크 모드라면 기본적으로 검은색 -> 흰색 변환 이런식일텐데,

라이트 모드라면? -> 검은색 색상 변수를 사용
다크 모드라면? -> 흰색 색상 변수를 사용

요런식으로 일괄적으로 적용될 수 있을 것입니당~

Comment thread app.js
return;
}

currentTodos.forEach((todo, index) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

forEach의 index를 todo 식별자로 사용하고 있는데,
지금은 render()에서 매번 리스트를 다시 그려서 괜찮지만,
다음 과제에서 react로 구현시 문제가 될 수 있습니다!


react는 변경된 요소만 재렌더링하기 때문에, 고유한 id를 주지 않는다면
중간 항목을 삭제하면 index가 밀리면서 어떤 항목이 삭제된 건지 올바르게 판단하지 못할 수도 있습니당


각 todo에 고유 id(crypto.randomUUID() (꼭 uuid를 무조건 쓰라는건 아닙니다 "고유한"에 좀 더 중점을 맞추시는게 좋음))
를 부여해주시는게 좋아용


참고글

Comment thread app.js
Comment on lines +156 to +161
/* ── Render All ── */
function render() {
currentDateEl.textContent = formatDisplayDate(selectedDate);
renderWeek();
renderTodos();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

다음 과제가 react 마이그레이션인 만큼,
render All 하는 부분에 대해서 react는 어떤 차이점을 가지지?
라는 점에 대해 생각해보시면 좋을거 같습니당

Comment thread app.js
if (savedTheme === "dark") {
document.body.classList.add("dark");
themeToggleBtn.textContent = "\u2600\uFE0F";
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

다크모드 상태를 localStorage에 저장해서 새로고침 후에도 유지되도록 구현한 점이 좋은 것 같습니다!
추가로 html 파일에서 버튼의 aria-label은 고정값인데, 다크/라이트 상태에 따라 "다크모드 켜기" / "라이트모드 켜기" 처럼 함께 바뀌면 접근성 면에서 더 좋을 것 같아요!

Comment thread index.html
class="todo-form__input"
id="todoInput"
placeholder="할 일을 입력하세요"
required
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

required를 넣어주셔서 빈 입력을 제출할 수 없도록 처리한 점이 좋았습니다!
별도의 복잡한 로직 없이도 기본적인 입력을 검증할 수 있다는 점이 좋은 것 같아요 :)

Comment thread app.js
} catch {
return {};
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

에러 상황을 대비해 try...catch로 예외 처리를 해두신 점이 좋았습니다!
localStorage 데이터가 깨져 있거나 예상과 다른 값일 때 앱이 바로 죽지 않도록 방어해둔 점이 안정적이라고 생각했어요. 덕분에 localStorage를 다룰 때 이런 식으로 방어적으로 작성할 수 있다는 걸 배울 수 있었습니다!

Comment thread app.js
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

주석으로 코드에 대한 설명을 자주 자세하게 작성해주셔서 코드를 전반적으로 이해하기 편했습니다! 특히 협업할 때 가지면 좋은 습관인 것 같습니다.

Comment thread app.js
li.appendChild(dayNumber);
li.appendChild(dayCount);

li.addEventListener("click", () => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

렌더링될 때마다 같은 요소에 이벤트를 새로 바인딩하면 성능 문제가 발생할 수 있습니다. weekDaysEl 등에 이벤트 위임하는 식으로 처리하면 성능 문제를 관리할 수 있을 것 같아요!
하단의 checkbox, deletebtn 등에 대해서도 todoList에 이벤트 위임을 해서 처리하면 더 좋을 것 같습니다.

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.

4 participants