본문 바로가기

Coding/내일배움캠프

[내일배움캠프] Node.js 4기 TIL | Day 14 | 24.01.11.(목)

[ (Part 1) JS개인과제리뷰 - 수강생 제출과제 코드리뷰 ]

Checklist

[필수요구사항]

- 순수 바닐라 자바스크립트 사용
- TMDB API 사용하여 데이터 가져오기
- 영화 카드리스트 UI 구현
- 영화 검색 UI 구현
- const, let 만을 이용한 변수 선언
- 화살표 함수 사용
- 배열 메소드 2개 이상 사용 : reduce, filter
- DOM 제어 API 2개 이상 사용 : getElementByClassName, innerHTML

[선택요구사항]

- 반응형 구현 : grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
- display grid 사용 : 영화 카드 리스트
- display flex 사용 : 영화 카드
- 대소문자 관계없이 검색 가능
- 검색 결과 없을 때 예외 처리
- reset.css로 기본 스타일 제거

[prettier 설정]

- 문서 잘 보고 적용해두자.

[reset.css]

assets / logo.png

[.prettierrc]

- code formatter
- 깃허브에 올려줘야 .. 팀플할 때 동일한 포맷으로 사용할 수 있다 ~

[index.html[

- <link rel="stylesheet" href="reset.css" />
- <link rel="stylesheet" href="ui.css" />

settings.json보다 .prettierrc의 설정이 더 우선시된다.

https://prettier.io/docs/en/configuration.html


[reset.css]

- 현업에서도 많이 사용하고, 많은 개발자 분들이 사용하는 css 파일
- 모든 브라우저에서 일관된 코드로 시작할 수 있게끔 초기화를 시켜주는 것 ..
- 브라우저마다 다를 수 있는 css 스타일은 통일시킨다.
- 일관된 margin이나 padding .. 등등등 .. 

https://meyerweb.com/eric/tools/css/reset/

[ui.css]


/////////////////////////////////////////////////////////////


html을 잇는 엔진 : html parser
css을 잇는 엔진 : css parser
js를 잇는 엔진 : js parser

html parser : html문서를 위에서부터 쭉 읽는다.
html parser가 html 문서를 쭉 읽는 행위를 html parsing이라고 한다.
html이 파싱이 되면 DOM Tree가 만들어진다.

DOM Tree가 만들어지면 뭐가 좋냐?
자바스크립트 코드를 이용해서 querySelector나 getElementsById .. 
DOM API를 사용해서 html에서 js를 컨트롤 할 수 있다.

html parser가 link .. 파일을 만나게 된다면 파일을 다운로드 받고 실행을 하게 된다.

header .. main

form .. semantic : 의미론적인 .. 

1. 검색 엔진이 여러분의 문서를 쉽게 찾게 하기 위해서는 .. form 태그처럼,
h1 태그처럼, header처럼, semantic 코드를 의미를 답으로 보고 예측을 할 수 있는 그런 코드를 써줘야
검색 엔진도 여러분의 문서를 분석할 때 어떤 문서구나 하는 것을 더 빠르게 더 쉽게 알아차릴 수 있습니다.
SEO(검색 엔진 최적화)에도 유리하다. 다른 사람이 내 코드를 언제든지 읽을 수 있다는 생각으로 작성을 하시는 게 좋다. 

form 태그 .. html 태그 중에 submit 이벤트라는 걸 가지는 태그이다.

form 태그를 사용했을 때 좋은 것 

이벤트 핸들러로 button에 onClick을 달아준다거나, input에 onChange를 달아준다거나,
별도로 이벤트 핸들러를 input이나 button 태그에 달아주지 않더라도,
form 태그의 자식으로 있으면 자동으로 input에서 enter를 쳤을 때 submit이 발생하고,
버튼을 클릭했을 때도 submit이 발생한다.

ul : unordered list : 굉장히 semantic한 태그이다.

ul 태그를 보면 예측할 수 있는 게 있다. 안에 li 태그가 있겠구나.

영화 1 영화 2 영화 3 .. 카드들이 동적으로 삽입이 되겠구나 .. 


/////////////////////////////////////////////////////////////

let으로 변수를 선언했기 때문에 .. 뭔가 밑에서 .. 데이터 재할당하는 코드가 있겠거니 ..

화살표 함수 .. 

fetch movie .. 

함수의 정의 / 호출 / 실행은 다르다 ~

실행을 해야 자바스크립트 엔진이 해당 함수 안으로 들어가서 코드를 읽기 시작한다.

load_movie() 함수가 가장 먼저 실행되는 함수이다 .. (해당 코드에서)

윈도우 .. Ctrl 누르면 클릭을 할 수 있게 바뀐다.. 함수 안으로 들어갈 수 있게 바뀐다 .. 

데이터를 받아오는 요청을 하는 것이 fetch이다.

tmdb 

fetch를 실행한 결과가 promise .. 

promise를 가지고 .then, .then, .then .. 

async .. await .. 

awiat 뒤에는 promise한 값만 나올 수 있다 ..

구조분해할당 ..

await 뒤에는 promise ~

F12 개발자 도구에서 확인할 수 있는 ==$0
구글에서 제공해주는 것 .. 

<ul class="movie-list"> == $0

콘솔창에 $0을 치면

<ul class="movie-list"> ... </ul>이 출력된다.

원래 ul 태그를 찍기 위해서는

document.querySelector("ul") 라고 작성해줘야 하는데, 번거롭지 않게 사용할 수 있다.

$0 .. 방금 내가 클릭했던 element를 출력준다 .. 

$0.innerHTML

ul 태그 안의 20개의 영화 리스트가 문자열로 변환되어 쭉 출력되는 것을 볼 수 있다.

innerHTML : ul 태그 안의 모든 자식들을 문자열화 한 것이구나 ..

innerHTML은 문자구나라는 걸 아실 수 있으십니다.

$0.innerHTML = "<h1>ㅎㅎㅎ</h1>"

ul 태그 안에 h1 태그 들어가는 걸 확인할 수 있다.

innerHTML에 할당되는 데이터는 문자열이구나 ~
→ movie_list.reduce( ( ... ) )의 결과값은 문자열이겠구나.
→ 이 값을 innerHTML에 할당하고 있기 때문에 ~ 

reduce라는 배열 메서드 .. 어떤 배열 메서드를 순회하며 ..
어떤 누적값을 모아서 .. 그 누적 값을 return해주는 게 목적인 메서드이다.

reduce(콜백함수, 누적값의 초기값);

초기값을 기준으로 누적을 해간다 .. 

함수 이름을 semantic하게 짓는 것도 개발자에게 중요한 능력이다 ~ 




li 태그에 하나의 속성으로 onclick을 넣고,
그 oncllick에 alert 함수를 직접 할당했다.

이런 방식을
event-handler-attribute 방식이라고 한다.

'event-handler를 binding, 할당을 했다'라고 한다.

"event-handler를 event-hanlder-attribute 방식으로 할당을 했다"라고 한다.



코드 사실 좀 아쉽다.. 밑에 갔다가 위에 갔다가 왔다갔다 해야 하는 부분이 있다.


h1 태그는 보통 제목을 입력하는 태그로 사용한다..

이미지의 경우 <figure> 태그를 사용하는 것이 조금 더 semantic하다.

바닐라 자바스크립트에서는 .. event-handler-attribute 방식은 권장되지 않는다.



html과 js는 기본적으로 관심사가 다르다.

html은 기본적으로 화면에 ui를 나타내는 부분이 첫 번째의 관심사이다..

js는 이미 나타나져 있는 ui를 기반으로 사용자와 interaction하는 데에 관심이 있다.

이렇게 html 태그에 event-handler-attribute 방식을 사용하는 것은

바닐라 자바스크립트에서 권장되지 않는 방식이다.

가능은 하지만, 권장되는 방식은 아니다.



자바스크립트의 함수명이나 변수명을 작성할 땐, camelCase를 사용한다.

camelCase : allMovieList
snake_case : all_movie_list

snake_case .. 파이썬에 익숙하신 분들은 이렇게 씁니다~

자바스크립트에서는 이렇게 안 쓰시는 게 좋겠습니다.


현재 코드에서는 ul 태그가 하나만 존재하는데, 이 경우 getElementsByClassName과 같이 복수형을 사용하는 것은 좋지 못하다.

(비권장)

movie_list_element = document.getElementsByClassName((_movie_list, movie_item) => { ... }

(권장)

movieListElement = document.querySelector(".movie-list")



toUpperCase() : 모두 대문자로 변환


* 구조분해할당 .. 



[ (Part 2) JS개인과제리뷰 - 파일디렉터리 셋업 및 모듈 개념 ]

html 파일, css 파일, js 파일 분리해서 관리할 것이다.

style .. script ..  하나의 파일 안에 전부 넣을 수도 있겠지만, 프로젝트 규모가 커지는 경우 관리에 어려움이 있다.


header

form

ul

<header></header>
<form></form>
<ul></ul>

html parser, javascript 엔진이 있다.

html 파서가 가다가 파일을 만나면 다운로드 받고 실행한다.

html 파서가 제어권을 js 엔진에 넘겨준다.

document 안에 있는 ul 태그를 찾으라고 명령했는데,
body 태그에 있는 부분은 아직 html parser가 파싱을 하기 전이다.

body 태그를 파싱해야 DOM Tree가 만들어진다.

자바스크립트 파일 실행이 끝나면, 자바스크립트 앤진이 다시 html 파서에게 제어권을 넘겨준다.

body 태그에 넣으면 잘 실행이 되는 걸 확인할 수 있다.

하지만, 나는 body 태그에 넣지 않고 head 태그에 넣고 싶다.

왜 head 태그에 넣고 싶냐?

다운로드 받는 동안 .. 앞에서 사용자들에게 조금이라도 더 빨리 화면을 보여주고 싶기 때문에 ..

어떻게 해야 html 파서가 파싱을 끝낸 다음에 자바스크립트를 실행하게 할 수 있을까?

script 태그 중 attribute 중 defer 라는 키워드가 있다. defer라는 속성 넣어주면 ul이 잘 나온다..

defer .. 지연되다..

script 태그 - js 실행을 지연 실행하겠다.

대신 백그라운드에서 다운로드를 받는다.

명령만 해두고 그대로 파싱을 끝까지 .. 

파싱이 다 끝난 다음에 자바스크립트 엔진에 제어권을 넘겨주고,

자바스크립트 엔진이 자바스크립트를 실행하도록 만든다.

defer라는 키워드가 있으면 다운로드를 받더라도,

html 파서가 일이 다 끝날 때까지 기다렸다가 실행된다. 지연 실행된다.


요즘 .. defer 요즘 잘 안 쓴다.

type="module"을 더 많이 사용한다.



- 모듈 (module)
- 특정 관심사에 해당하는 기능을 수행하는 변수와 함수의 모음
- 관심사의 분리 (재사용성, 유지보수성, 깃 협업능률 향상)

// 1. 영화 데이터를 가져와서 화면에 나타내기

// 2. 영화 검색


<script type="module" src="./src/main.js"></script>
<script type="module" src="./src/movie.js"></script>
<script type="module" src="./src/search.js"></script>

이렇게 script 태그를 각각 적용할 수도 있다.

이렇게 했을 때 큰 문제는 없다.

type="module"이라는 단어가 없으면 같은 scope 안에 존재하게 된다.

같은 scope 안에 존재하게 된다. 이게 무슨 뜻이냐?

같은 scope이란 뜻은 같은 공간에 존재한다는 뜻이다.

let movies;

let movies;

와 같은 상황이라는 뜻

독립적인 scope를 보장해주기 위해.. 변수명 겹칠 수 있도록 ..

똑같은 변수명 사용해도 문제가 생기지 않는다.

각 type마다 독립적인 scope를 가지고 있다.

export : 나를 가져다 쓰시오 .. 

import { getMovies } from "./movies.js";

export를 사용하면, 다른 모듈 파일에서 다른 모듈 파일에 있는 함수나 변수를 가져다 쓸 수 있구나!

import 나 export 를 사용하기 위해서는 type="module"을 선언해줘야 한다.

import 문에서 .. 파일 다운로드 받아서 실행하는 것이다 .. 

다운로드 받고 실행하고 그 다음을 읽는다 .. 

main.js
- Application의 전체 로직을 확인할 수 있는 파일

movie.js
- 영화 정보를 가져와서 UI에 리스팅하는 기능을 담당

search.js
- 원하는 제목의 영화만 검색(필터링)하는 기능을 담당


Strict Mode 기본 내장

"use strict"

// 변수 선언 업시 즉시 사용 방지
a = 10;
console.log(a); // Uncaught ReferenceError : a is not defined

// 예약어를 변수명으로 사용 방지
let arguments; // Invalid use of 'arguments' in strict mode.



:root {
/* 문서의 최상위 요소를 의미, html과 사용할 경우 <html>을 의미 */
}

/* 주로 테마 색상들은 변수로 관리 */

:root {
--bg-header-color: #ffe194;
--bg-card-color: bisque;
}

header {
background-color: var(--bg-header-color);
}

* C++에서의 #define과 유사하다.

[ (Part 3) 튜터 코드 리뷰 및 JS 핵심 로직 ]

focus 함수 .. 깜박깜박 .. 

innerHTML : 문자열

배열에 map 메소드 돌리면 배열이다.

.join : 배열을 문자열로 만들어주는 수단

Array.prototype.join()



const movies = [ { title: "제목1" }, { title : "제목2" }, { title : "제목3" } ]
const movieTItles = movies.map(movie => `<h1>${movie.title}</h1>`);
console.log(movieTItles);

// ["<h1>제목</h1>", "<h1>제목2</h1>", "<h1>제목3</h1>"

ul 태그에 click-event-handler를 심어두면 .. 
'

// 이벤트 위임 : 하위 요소에서 발생한 이벤트를 상위 요소에서 처리하도록 해줍니다.
function handleClickCard(event) {
// 카드 외 영역 클릭 시 무시
if (even.target === cardList) return;

if (event.target.matches(".movie-card")) {
alert(`영화 id: ${event.target.id}`);
} else {
// 카드의 자식 태그 (img, h3, p) 클릭 시 부모의 id로 접근
alert(`영화 id: ${event.target.parentNode.id}`);
}
}


- 부모 요소인 ul 태그 이벤트 핸들러가 등록되어 있으면 자식 요소인 li, img, h3, p 태그 중 어떤 것을 클릭해도 부모 요소의 이벤트 핸들러가 실행된다.

- 이벤트 위임을 잘 다루려면 event.target, event.currentTarget의 차이를 알아야 한다.
- event.target : 이벤트 발생한 요소
- event.currentTarget : 이벤트 핸들러가 등록되어 있는 요소

- 이벤트 위임이란 게 어떻게 가능하지? → "이벤트 버블링"이란 특징 때문
- 이벤트버블링이란? 하위 요소에서 발생한 이벤트가 상위 요소로 전파되는 현상

이벤트 발생 시 이벤트 전파흐름

Child → Parent → Grand Parent


eventPhase 1. Capturing phase

windows → document → html → body → ul → li

eventPahse 2. Target phase - event target

eventPhase 3. Bubbling phase

li → ul → body → html → document → windows

이벤트 전파는 전파고, 이벤트 전파를  캡쳐해서 이벤트 핸들러를 실행시키는 건 별도이다.

기본은 버블링 . 캡처는 옵션을 줘야 한다.

ui만 맞춰주면 .. 하위에도 위임 가능 ~



어디 클릭했는지 예외 처리 잘 해주면 .. 단 하나의 이벤트 핸들로만으로도 충분하다고 한다.



form 태그

- semantic tag : 폼 내부에 사용자 입력을 받고 제출하는 UI가 있을 것이라 예측 가능
- submit 이벤트 발생 시 새로고침하는 기본 동작을 가지고 있음

forElement.addEventListener('submit', function (event) {
// 발생한 이벤트에 대한 브라우저의 기본 동작(새로고침)을 막습니다.
event.preventDefault();
})

for 내부에서 input과 button의 동작

- for 태그에 submit 이벤트 핸들러가 있는 경우, input에 내용 입력 후 button 클릭 또는 Enter 입력 시
submit 이벤트 핸들러가 실행된다.
- form 안에 있는 button 태그에 type을 명시하지 않은 경우 기본 type은 submit이며, submit이 아닌 다른 타입을 명시하면 버튼 클릭 시 다른 타입을 명시하면 버튼 클릭 시 submit 이벤트가 발생하지 않는다.

<form id="search-form">
<label> 영화 검색 : </label>
<input type="text" id="search-input?" placeholder="영화 제목을 입력해 보세요"
<button type="submit" id="search-btn">검색<button>

event.preventDefault .. 새로고침 .. 

toUpperCase();
towLowerCase();

DOM 활용하면 .. 카드 .. li 태그 .. 속성 .. display .. css 파일 접근 .. 


이벤트 핸들러

- 이벤트 핸들러란 이벤트가 발생했을 때 실해되는 함수
- 매개변수로 event 객체를 받을 수 있음

Element.addEventListner(`click`, function (event) {
console.log(event);
})



async/await

- async 함수는 항상 Promise를 반환한다.
- await 뒤에 있는 건 항상 Promise이다.
- await Promise 는 Promise Result 반 반환하며 약속이행이 될 떄까지 기다린다.



async function printData() {
const response = await fetchData( );
console.log("response: ", response);
const result = await response.json();

async function fetchData(  {
const result = await fetch('https://jsonplaceholder.typicode.com/posts/1')
return result;

printData ;

* ync - await 꼭 숙지하기

await 뒤에 있는 건 무조건 promise이다.

await .. 비동기 함수에게 순서 대로 못 정한ㄴ다 .. .

await .. 동기함수에게 실행 양보 안 한다 .. ☆☆☆