Skip to content

Latest commit

 

History

History
161 lines (142 loc) · 12.7 KB

20210324.md

File metadata and controls

161 lines (142 loc) · 12.7 KB

JavaScript

인상 깊은 조언

  • 마음을 차분히 하고 문제부터 꼼꼼히 읽을 것.
  • 프론트엔드가 하는 일은 결국 백엔드가 준 필요충분한 자료(=군더더기 없는 자료)로 html을 만들어내는 것이다.

Pair Programming HOF 문제 관련 해설

  • 1번 문제: id: 중복되지 않는 숫자정보로써, 시간적 개념으로 바라볼 필요가 있다(적은 숫자가 가장 먼저 만들어진 자료). 최신 자료가 가장 위에 쌓이며 원칙적으로 sorting은 backend에서 해서 줘야 하는 것이 간단하고 이치에 맞다.
    • checkbox: default는 unchecked인데, checked로 바꾸려면 HTML5 이전에는 checked="checked"로 써야했지만 이제는 해당 checked만 써두면 된다.
    • 배열과 배열 속 요소의 식별자는 복수-단수 형태로 하는 것이 가독성을 위한 스킬이자 컨벤션. todos 배열 속의 item들은 todo로 명명하여 인수로 주기.
    • 템플릿 리터럴 속의 인터폴레이션에 매번 객체이름을 넣어 프로퍼티 참조를 하고 싶지 않다면 디스트럭쳐링 할당을 화살표함수의 인수에 활용할 수 있다.
function render(){
  return todos.map(({id, content, completed}) => {
    return `<li id="${id}">
    <label><input type="checkbox" ${ completed ? "checked" : "" }>${content}</label>
    </li>`
  }).join('');
}
  • 3번 문제: sort() 안에 넣을 콜백함수 인수도 a, b로 하지 말고 todo1, todo2 등으로 명명해주면 훨씬 이해하기 쉬운 코드를 작성할 수 있다.
  • 5번 문제: 사용자는 기대하는 타입의 값을 넣지 않는다. 숫자를 받아서 해당 숫자를 id로 갖는 객체에 작업하려고 하는데 만약 문자열로 데이터가 들어올 경우 비교연산자의 매개변수로 들어오는 식별자(e.f. todo.id === id)에 +로 숫자 타입캐스팅을 해주면 보다 안전하게 만들 수 있다.
  • 7번 문제: 화살표함수의 리턴값을 객체로 줄 때, 그리고 화살표함수의 인수를 객체 디스트럭쳐링 할당으로 줄 때 JS엔진은 {}가 코드블럭인지 객체인지 판단하지 못해 오류를 일으킨다. 그러므로 꼭 ({})의 형태로 작업할 것.
  • 9번 문제: Math.mas()의 인수에 아무것도 전달되지 않으면 -Infinity를 리턴하므로, 만약 배열을 풀어 넣어 인수로 주고 싶으면 0을 같이 주거나 인수에 삼항조건연산문으로 todos.length? todos.map(todo => todo.id) : 0을 넣어줄 것
let todos = [
  { id: 3, content: 'HTML', completed: false },
  { id: 2, content: 'CSS', completed: true },
  { id: 1, content: 'Javascript', completed: false }
];

function getMaxId() {
  return Math.max( ... todos.length ? todos.map(todo => todo.id) : 0);
}

console.log(getMaxId()); // 3

디스트럭쳐링 할당

배열 디스트럭쳐링 할당

  • 식별자가 올 자리에 배열, 객체 리터럴을 넣고 그 안에 위치한 값의 자리에 식별자를 넣으면 해당하는 값이 식별자에 할당된다.
// 편의상 각 줄은 서로다른 파일이라 생각하고 중복선언을 피하는 걸로 생각한다.
// 편의상 주석은 할당문이 아닌 식별자가 가진 값을 가리키는 것으로 생각한다.
const [a, b] = [1, 2];	// a = 1, b = 2
const [b, a] = [2, 1];	// a = 2, b = 1
const [a] = [1, 2];	// a = 1
const [a, b, c] = [1, 2];	// a = 1, b = 2, c = undefined
const [a, b, c] = [1, , 3];	// a = 1, b = undefined, c = 3
  • 주목할만한 흥미로운 점: const 키워드는 원래 선언과 초기화가 필수인데 디스트럭쳐링 할당에서는 초기값이 할당되지 않으면 에러가 아닌 undefined가 할당되는 현상이 일어난다.

객체 디스트럭쳐링 할당

  • 배열은 순서를 기준으로 할당했던 반면, 객체는 key를 기준으로 값을 할당한다.
const { a, b } = { a : 1, b : 2 };	// a = 1, b = 2
const { b, a } = { a : 1, b : 2 };	// a = 1, b = 2
  • 인수가 객체인 경우에는 매개변수에 디스트럭쳐링 할당을 하면 식별자에 인수의 객체 내 프로퍼티 값을 바로 넣어줄 수 있다.

DOM (Document Object Model)

브라우저의 역할

  • 브라우저는 내 컴퓨터에서 동작하므로, 서버에 있는 리소스를 요청하여 받아와야 하는데, 이 때 서버에서 리소스는 랜선을 타고 날아온다.
  • 브라우저의 역할은 다음과 같다.
    1. 주소창을 통해 서버에 리소스를 요청한다. (= request)
    2. 요청하여 전달받은 리소스로, HTML과 CSS를 재료로 하여 브라우저 창을 색칠한다. (= rendering)
  • HTML 마크업 작업은 내 컴퓨터에서 하더라도 결국 서버에 갖다놔야 하는데, 이를 배포라고 한다.

브라우저의 렌더링 과정

  • 주소창에 naver.com을 치면 네이버의 수천대의 서버 중 메인 페이지 리소스를 가지고 있는 하나의 서버로 요청이 간다.
  • 클라이언트가 찾아가서 접속을 해야 통신을 통해 리소스를 받을 수 있다.
  • 서버에는 랜카드라는 것이 있는데 랜카드의 일련번호는 naver.com이라는 주소와 매핑되어 있다.
  • 매핑만 관리하는 서버를 DNS(Domain Name System)이라고 하는데, 주소창에 URL을 입력하면 URL에 입력된 문자열 즉 호스트 이름이 DNS를 통해 변환되어 해당 주소를 갖는 서버에게 요청을 전송한다.
  • 그냥 naver.com만 쓰면 기본적으로 루트 요청을 한 것으로 간주해 index.html을 보내준다.
  • index.html 의 html 태그에서도 또다른 요청을 보낸다. (e.g. img src에서는 이미지 소스를 요청)
  • 그러나 위와 같은 요청들은 html에 종속되어 있으며 html이 왕초이다.

HTML 파싱과 DOM 생성

  • HTML은 사람이 읽을 수 있도록 만들어진 문자열인데, 이를 브라우저가 이해하려면 각 문자를 해석해야 한다. 그 해석을 parsing이라고 하며 parsing의 결과물이 DOM.
  • HTML 태그로 시작하고 닫히며 html 태그는 단 두 개의 자식요소(head, body)를 갖는다.
  • html 파일을 parsing하면 DOM이라는 자료구조가 생성되는데, 부모자식관계로 각 요소노드가 표현되는 Tree 자료구조이다.
<!DOCTYPE> // 이것은 요소로 치지 않는다.
<html>
  <head>
  </head>
  <body>
    <ul>
      <li>Apple</li>
      <li>Banana</li>
      <li>Orange</li>
    </ul>
  </body>
</html>
  • 위의 html은 루트인 documenthtml 아래 head, body, 그리고 bodyul, ulli들, li 밑에 각각의 텍스트 노드를 갖는다.
  • document: 루트이며 진입점이다. document를 통해서만 이 DOM tree 자료구조에 들어올 수 있다. DOM TREE를 조작하려면 무조건 document.querySelector() 등 document를 통해야 한다.
  • 루트 외에 중간이나 끝에 있는 요소들을 node라고 부른다.
  • JS를 통해 DOM을 조작하는 순간 repaint가 된다.
  • JS가 하는 일은 결국 HTML로 만들어진 DOM Tree를 조작하여 정적인 화면을 동적으로 만드는 것이다
const $apple = document.getElementById('apple'); // 요소노드임을 명확히 하기 위해 식별자에 달러 사인을 붙인다.
$apple.textContent = 'Grape'	// HTML 텍스트를 조작
$apple.style.color = 'red'	// CSS 스타일링을 조작

HTML 요소 조작하기

  • html 마크업 태그는 HTML 요소라고 부르며, 이를 parsing한 결과로 생성된 것은 HTML 요소 노드 객체라고 부르자.

HTML 요소 참조

  • querySelector({CSS 선택자와 동일한 이름}): 처음 참조된 값만 가져온다.
    • 태그명으로 요소를 가져오는 것은 위험하기 때문에 좋은 방법이 아니다.
    • id로 가지고 올 때는 getElementById({id})를 사용한다.
  • CSS에서는 케밥케이스를 쓰지만 JS에서 스타일을 조작할 땐 같은 내용을 카멜케이스로 바꿔서 사용한다. (background-color => backgroundColor)
  • class 이름으로 탐색된 첫 요소를 가지고 올 때는 querySelector에 CSS처럼 클래스명 앞에 .을 붙인다.
  • class 이름으로 탐색된 모든 요소를 가져오려면 querySelectorAll을 쓰는데, 이 프로퍼티의 값은 Nodelist라는 자료구조의 형태로 리턴된다. Nodelist는 유사배열객체이며 iterable이다.
  • 배열로 변환해서 배열메서드를 쓰는 것이 편하다. [ ... Nodelist ] 또는 [ ... HTMLCollection ]으로 만들어 배열메서드로 각 요소를 순회하며 작업할 것.

Traversing

  • 특정 요소에 접근한 후 이를 통해 다른 요소에 작업하는 것
<ul class="fruits">
  <li class="apple">Apple</li>
  <li class="banana">Banana</li>
  <li class="orange">Orange</li>
</ul>
  • 위와 같은 html에서 ul의 클래스명인 'fruits'를 통해 document.querySelector('.fruits').children 또는 document.querySelector('.fruits').childNodes로 자식요소를 가져올 수 있다.
    • document.querySelector('.fruits').children: HTMLCollection이라는 유사배열객체의 자료구조로 자식요소 정보를 준다.
    • document.querySelector('.fruits').childNodes: 엔터와 스페이스바로 입력된 모든 공백텍스트노드까지 가져온다. 공백을 가지고 작업할 일은 없으니 사용을 지양해야.
  • 동일한 문제가 firstElementChildfirstChild, lastElementChildlastChild에도 발생한다. 전자는 공백 텍스트노드를 제외한 첫 요소, 마지막요소가 취득되고, 후자는 공백텍스트노드가 취득된다.
  • 첫째/막내 외의 중간 자식들에 접근하는 방법은 첫째/막내를 통하는 방법밖에는 없다. 위와 동일한 이슈를 갖는 previousElementSibling, previousSibling, nextElementSibling, nextSibling을 사용해 탐색하여 취득할 수 있다.
  • 부모노드 또한 traversing이 가능하다. parentNode라는 프로퍼티로 취득할 수 있는데, 부모요소는 절대 텍스트노드가 될 수 없으므로 무조건 요소노드객체가 취득된다.

querySelectorAll vs. 부모요소에서 children

  • querySelectorAll: 클래스명이 같은 모든 요소에 작업이 되기 때문에 위험한 방법.
  • 부모요소에서 접근: 코드 자체에서 내가 작업하려는 범위를 알 수 있으며 그 범위 안의 요소들에게만 작업이 되기 때문에 안전하다.

콘텐츠 바꾸기

  • textContent: 클래스명을 사용하여 참조한 요소 노드 객체의 textContent를 재할당하면 HTML 마크업을 넣어줘도 문자열로 인식해서 text처럼 브라우저에 렌더링된다.
  • innerHTML: 요소 안의 콘텐츠영역에 유효한 HTML 마크업을 넣어주려면 innerHTML 프로퍼티 값을 재할당(갱신) 해주면 parsing되면서 DOM 요소 노드객체로 만들어진 후 텍스트가 들어온다.
    • 이는 매우 편리하지만 innerHTML을 통해 스크립트 코드가 들어올 경우 XSS 공격이라고도 불리는 JS를 통한 조작과 실행이 이뤄질 수 있다.
    • 사용자가 입력하는 데이터는 untrusted data이므로 아예 입력할 수 없게 하는 게 원칙이지만, 그렇게 할지라도 살균해주는 library를 사용하여 innerHTML로 들어오는 텍스트 속 스크립트를 모두 제거해줘야 한다.

Attribute 조작

  • getElementById로 취득한 요소에 id를 마침표연산자로 참조하면 해당 태그의 id값이 나온다.
  • querySelector로 취득한 요소에 class를 동일하게 참조하면 나오지 않는다. class는 JS의 예약어이기 때문에 메서드명으로 사용하지 않으므로 다음 두 메서드로 참조해야만 한다.
    • className: class라는 어트리뷰트가 가진 문자열을 그대로 알려주는데, 여러 개의 class 있을 경우에도 공백과 함께 문자열 1개가 온다.
    • classList: 해당 요소가 가진 모든 클래스명을 객체로 리턴
  • classList 메서드
    • classList.contains: 인수로 넣은 클래스명이 있는지 확인
    • classList.add: 인수로 넣은 클래스명을 더할 수 있다.
    • classList.remove: 인수로 넣은 클래스명을 삭제할 수 있다.
    • classList.toggle: 인수로 넣은 클래스명이 있으면 삭제, 없으면 추가

느낀 점

  • 드디어 DOM을 통해 HTML과 CSS를 조작하는 JavaScript의 진정한 파워를 살짝 엿보았다. HTML 배울 때부터 javascript는 DOM을 통해 이 모든걸 조작할 수 있다는 이야기를 누누히 들어왔는데, 이걸 직접 눈으로 보고 해보니 과장을 조금 보태자면 온 몸에 전율이 돈다.
  • 이전에 왜 이렇게 쓰는지 몰랐던 많은 복잡한 글자들이 이제는 이유를 알게 되어 기쁘다.