Study/모던 자바스크립트 Deep Dive
[모던 자바스크립트 Deep Dive] 36장 ~ 40장
chaeon1
2025. 5. 11. 01:06
36장 디스트럭처링 할당
- 배열이나 객체에서 값을 추출해 변수에 개별적으로 할당하는 문법
- 이터러블 또는 객체 리터럴에서 필요한 값만 뽑을 때 유용
36.1 배열 디스트럭처링 할당
- 기본 문법
const [a, b] = [1, 2];
- 인덱스 기준으로 순서대로 할당
- 할당 대상은 반드시 이터러블
- 에러 예시:
const [x, y] = {}; // TypeError
- 에러 예시:
- 변수 수와 요소 수의 일치는 필요하지 않음
- 부족 시
undefined
, 초과 시 무시
- 부족 시
- 기본값 설정 가능
const [a, b = 10] = [1]; // a:1, b:10
- Rest 요소 사용 가능
const [x, ...y] = [1, 2, 3]; // x:1, y:[2,3]
- 예시 활용: URL 파싱 시 필요한 값만 추출
36.2 객체 디스트럭처링 할당
- 기본 문법
const { key1, key2 } = obj;
- 키 이름 기준, 순서 상관 없음
- 변수 이름 변경 가능
const { key1: newName } = obj;
- 기본값 설정 가능
const { key = 'default' } = obj;
- 함수 매개변수에도 사용 가능
function fn({ id }) { ... }
- 배열 요소가 객체인 경우 혼용 가능
const [, { id }] = todos;
- 중첩 객체 접근
const { address: { city } } = user;
- Rest 프로퍼티 사용
const { x, ...rest } = obj;
37장 Set과 Map
37.1 Set
- Set: 중복되지 않는 유일한 값들의 집합
구분 배열 Set 객체 동일한 값을 중복하여 포함할 수 있다. O X 요소 순서에 의미가 있다. O X 인덱스로 요소에 접근할 수 있다. O X - Set 객체 생성:
new Set(iterable)
- 중복값 자동 제거
- 배열 중복 제거:
[...new Set(array)]
- 요소 추가:
.add(value)
- 중복 무시, 체이닝 가능
- 요소 존재 여부 확인:
.has(value)
- 요소 삭제:
.delete(value)
(불리언 반환) - 요소 일괄 삭제:
.clear()
- 요소 순회
.forEach((v, v2, set))
-> 콜백에서 v와 v2는 동일함for...of
, 스프레드, 디스트럭처링 가능
- 집합 연산
- 교집합:
intersection(set)
- 합집합:
union(set)
- 차집합:
difference(set)
- 상위 집합 여부 확인:
isSuperset(set)
- 교집합:
37.2 Map
- Map: 키와 값의 쌍으로 이루어진 컬렉션
구분 객체 Map 객체 키로 사용할 수 있는 값 문자열 또는 심벌 값 객체를 포함한 모든 값 이터러블 X O 요소 개수 확인 Object.keys(obj).length
map.size
- Map 객체의 생성:
new Map([[key1, value1], [key2, value2]])
- 중복 키 존재 불가능 (덮어쓰기)
- 요소 개수 확인:
.size
- 요소 추가:
.set(key, value)
- 체이닝 가능
- 요소 취득:
.get(key)
- 요소 존재 여부 확인:
.has(key)
- 요소 삭제:
.delete(key)
(불리언 반환) - 요소 일괄 삭제:
.clear()
- 요소 순회
.forEach((value, key, map))
for...of
로 순회 ([key, value]
쌍)- 스프레드, 배열 디스트럭처링 가능
- 이터러블 메서드
Map 메서드 설명 Map.prototype.keys Map 객체에서 요소키를 값으로 갖는 이터러블이면서 동시에 이터레이터인 객체를 반환한다. Map.prototype.values Map 객체에서 요소값을 값으로 갖는 이터러블이면서 동시에 이터레이터인 객체를 반환한다. Map.prototype.entries Map 객체에서 요소키와 요소값을 값으로 갖는 이터러블이면서 동시에 이터레이터인 객체를 반환한다.
38장 브라우저 렌더링 과정
- 브라우저는 HTML, CSS, 자바스크립트, 이미지, 폰트 파일 등 렌더링에 필요한 리소스를 요청하고 서버로부터 응답을 받는다.
- 브라우저의 렌더링 엔진은 서버로부터 응답된 HTML과 CSS를 파싱하여 DOM과 CSSOM을 생성하고 이들을 결합하여 렌더 트리를 생성한다.
- 브라우저의 자바스크립트 엔진은 서버로부터 응답된 자바스크립트를 파싱하여 ASTAbstrad Sylax Tree를 생성하고 바이트코드로 변환하여 실행한다. 이때 자바스크립트는 DOM API를 통해 DOM이나 CSSOM을 변경할 수 있다. 변경된 DOM과 CSSOM은 다 시 렌더 트리로 결합된다.
- 렌더 트리를 기반으로 HTML 요소의 레이아웃(위치와 크기)을 계산하고 브라우저 화면에 HTML 요소를 페인팅한다.
38.1 요청과 응답
- 브라우저 주소창에 URL 입력 -> DNS -> IP -> 서버에 HTTP 요청
- 루트 요청은 일반적으로
index.html
응답 - HTML 파싱 중 외부 리소스를 만나면 해당 리소스를 서버에 요청
<link>
,<script>
,<img>
등
38.2 HTTP 1.1과 HTTP 2.0
- HTTP 1.1
- 커넥션 당 1개 요청/응답
- 동시성 낮음, 리소스 많을수록 느림
- HTTP 2.0
- 하나의 커넥션으로 다중 요청/응답 가능
- 속도 향상 (~50%)
38.3 HTML 파싱과 DOM 생성
- HTML -> 바이트 -> 문자열 -> 토큰화 -> 노드 생성 -> DOM 트리
- HTML 요소의 중첩 관계는 부모-자식 트리 구조로 반영
38.4 CSS 파싱과 CSSOM 생성
<link>
,<style>
태그를 만나면 HTML 파싱 일시 중단- CSS -> 바이트 -> 문자열 -> 토큰 -> 노드 -> CSSOM 생성
- 상속 정보 포함된 스타일 트리
38.5 렌더 트리 생성
- DOM + CSSOM -> Render Tree
- 화면에 표시되지 않는 요소(
<meta>
,display: none
) 제외 - 렌더 트리 -> Layout 계산 -> Paint 처리
38.6 자바스크립트 파싱과 실행
<script>
태그를 만나면 HTML 파싱 중단, JS 파싱/실행- JS -> Tokenizing -> AST 생성 -> 바이트코드 변환 -> 실행
- DOM API로 DOM/CSSOM 변경 가능 -> 다시 렌더 트리 생성
38.7 리플로우와 리페인트
- 리플로우: 레이아웃 재계산 (크기/위치 변경 등)
- 리페인트: 시각적 스타일 변경 (색상만 바뀔 경우 등)
- 자주 발생하면 성능 저하의 원인
38.8 자바스크립트 파싱에 의한 HTML 파싱 중단
<script>
: HTML 파싱 블로킹, DOM 완성 전에 JS 실행되면 에러 발생 가능- 해결 방법
- 스크립트를
<body>
맨 아래에 위치 - async/defer 사용
- 스크립트를
38.9 script 태그의 async/defer 어트리뷰트
async
: HTML 파싱 도중 JS 다운로드, 즉시 실행 (순서 보장 X)defer
: JS 다운로드는 병렬, 실행은 DOM 생성 후 (순서 보장 O)
39장 DOM
- DOM(Document Object Model): HTML 문서를 트리 구조로 표현한 객체 모델
- HTML 문서를 파싱하여 요소, 속성, 텍스트 등을 노드 객체로 변환
- 계층적으로 구성, 각 노드는 객체로 제어 가능
39.1 노드
- DOM은 HTML 요소를 노드로 구성된 트리 자료구조로 표현
- 노드 객체의 타입
- 문서 노드(document): 루트 노드(
document
) - 요소 노드(element): HTML 요소 (
<div>
,<li>
등) - 어트리뷰트 노드(attribute): 요소의 속성
- 텍스트 노드(text): 요소 내부 텍스트
- 주석(Comment), 문서 타입(DocumentType), DocumentFragment 등
- 문서 노드(document): 루트 노드(
- 노드 객체의 상속 구조
- 노드는 브라우저가 제공하는 호스트 객체
- 상속 구조
Object
→EventTarget
→Node
→Element
→HTMLElement
→HTMLInputElement
등
- 공통 기능은 상위에서, 개별 기능은 하위에서 제공 (
input.value
,div.innerText
등)
39.2 요소 노드 취득
- id를 이용한 요소 노드 취득
document.getElementById(id)
- 하나의 요소만 반환, 없으면
null
- 태그 이름을 이용한 요소 노드 취득
document.getElementsByTagName(tagName)
HTMLCollection
반환 (live)
- class를 이용한 요소 노드 취득
document.getElementsByClassName(className)
HTMLCollection
반환 (live)
- CSS 선택자를 이용한 요소 노드 취득
document.querySelector(selector)
-> 첫 번째 요소document.querySelectorAll(selector)
->NodeList
반환 (non-live)
- 특정 요소 노드를 취득할 수 있는지 확인
element.matches(selector)
→ true/false
- HTMLCollection과 NodeList
HTMLCollection
getElementsByTagName
,getElementsByClassName
반환- live 객체: 요소 변경 시 자동 반영
- 순회 중 요소 변경 시 예상치 못한 결과 발생 가능
NodeList
- 대부분 non-live 객체,
childNodes
는 live 객체 forEach
등 일부 배열 메서드 지원
- 대부분 non-live 객체,
- 배열로 변환
[...collection]
,Array.from(collection)
활용- 배열 고차 함수(map, filter 등) 사용 가능
39.3 노드 탐색
- Node, Element 탐색 프로퍼티
Node.prototype
:parentNode
,previousSibling
,firstChild
,childNodes
제공Element.prototype
:previousElementSibling
,nextElementSibling
,children
프로퍼티 제공
- 공백 텍스트 노드
- HTML 문서의 공백(스페이스, 엔터 등)도 텍스트 노드로 취급되어 DOM 탐색 시 영향을 줄 수 있음
- 자식 노드 탐색
프로퍼티 설명 Node.prototype.childNodes
자식 노드를 모두 탐색하여 DOM 컬렉션 객체인 NodeList
에 담아 반환한다.childNodes
프로퍼티가 반환한NodeList
에는 요소 노드뿐만 아니라 텍스트 노드도 포함되어 있을 수 있다.Element.prototype.children
자식 노드 중에서 요소 노드만 모두 탐색하여 DOM 컬렉션 객체인 HTMLColLection
에 담아 반환한다.children
프로퍼티가 반환한 HTMLCollection에는 텍스트 노드가 포함되지 않는다.Node.prototype.firstChild
첫 번째 자식 노드를 반환한다. firstChild
프로퍼티가 반환한 노드는 텍스트 노드이거나 요소 노드다.Node.prototype.lastChild
마지막 자식 노드를 반환한다. LastChiLd
프로퍼티가 반환한 노드는 텍스트 노드이거나 요소 노드다.Element.prototype.firstElementChild
첫 번째 자식 요소 노드를 반환한다. firstElementChild
프로퍼티는 요소 노드만 반환한다.Element.prototype.lastElementChild
마지막 자식 요소 노드를 반환한다. LastELementChiLd
프로퍼티는 요소 노드만 반환한다. - 자식 노드 존재 확인
hasChildNodes()
는 텍스트 포함 확인- 요소만 확인할 땐
children.length
나childElementCount
사용
- 부모 노드 탐색:
Node.prototype.parentNode
사용 - 형제 노드 탐색
프로퍼티 설명 Element.prototype.previousElementSibling
부모 노드가 같은 형제 요소 노드 중에서 자신의 이전 형제 요소 노드를 탐색하여 반환한다. previousElementsibling
프로퍼티는 요소 노드만 반환한다.Element.prototype.nextElementSibling
부모 노드가 같은 형제 요소 노드 중에서 자신의 다음 형제 요소 노드를 탐색하여 반환한다. nextELementSibLing
프로퍼티는 요소 노드만 반환한다.Node.prototype.previousSibling
부모 노드가 같은 형제 노드 중에서 자신의 이전 형제 노드를 탐색하여 반환한다. previousSibling
프로퍼티가 반환하는 형제 노드는 요소 노드뿐만 아니라 텍스트 노드일 수도 있다.Node.prototype.nextSibling
부모 노드가 같은 형제 노드 중에서 자신의 다음 형제 노드를 탐색하여 반환한다. nextSibling
프로퍼티가 반환하는 형제 노드는 요소 노드뿐만 아니라 텍스트 노드일 수도 있다.
39.4 노드 정보 취득
nodeType
: 노드 타입 숫자- 1 (요소), 3 (텍스트), 9 (문서) 등
nodeName
: 노트 이름DIV
,#text
,#document
등
39.5 요소 노드의 텍스트 조작
nodeValue
: 텍스트 노드의 값을 읽거나 수정할 수 있는 getter/settertextContent
: 요소 노드의 모든 텍스트(자식 포함)를 가져오거나 설정 가능, HTML 태그 무시textContent
는 전체 텍스트,nodeValue
는 텍스트 노드만 접근 가능
39.6 DOM 조작
innerHTML
- 요소의 HTML 마크업을 문자열로 읽거나 설정
- XSS 위험 존재
insertAdjacentHTML
메서드- 기존 노드를 제거하지 않고 위치 지정하여 삽입
'beforebegin'
,'afterbegin'
,'beforeend'
,'afterend'
위치 지정 가능
- 노드 생성과 추가:
document.createElement()
,createTextNode()
- 노드 삽입:
appendChild()
,insertBefore()
로 DOM에 추가 - 노드 복사:
cloneNode(true|false)
- 노드 교체:
replaceChild(newNode, oldNode)
- 노드 삭제:
removeChild(child)
- DocumentFragment`
- 가상 컨테이너
- DOM 변경 최소화를 위해 사용
- 추가 시 자신은 제거되고 자식 노드만 DOM에 삽입됨
39.7 어트리뷰트
attributes
- 요소 노드의 모든 어트리뷰트 노드 집합
NamedNodeMap
객체로 반환getAttribute()
,setAttribute()
: 어트리뷰트 직접 접근/설정
- HTML 어트리뷰트 vs. DOM 프로퍼티
- 어트리뷰트는 초기 상태, DOM 프로퍼티는 현재 상태
value
,checked
는 변하고,id
,class
는 연동
dataset
data-
어트리뷰트를 JS 객체로 관리dataset.key = 'value'
로 접근 및 수정
39.8 스타일
- 인라인 스타일 조작
style
프로퍼티- camelCase로 사용
- 클래스 조작
className
,classList
add
,remove
,toggle
,contains
,replace
등 제공
- 요소에 적용되어 있는 CSS 스타일 참조
getComputedStyle(element)
- 상속 포함 모든 스타일 취득
- 의사 요소 지원
40장 이벤트
40.1 이벤트 드리븐 프로그래밍
- 사용자의 행위(클릭 등)를 감지하고 그에 따라 함수 실행
- 브라우저가 이벤트 감지 -> 개발자가 이벤트 핸들러 등록 -> 브라우저가 이벤트 발생 시 호출
onclick = 함수
방식으로 등록 가능
40.2 이벤트 타입
- 마우스 이벤트:
click
,dblclick
,mousedown
,mouseup
,mousemove
,mouseover
,mouseout
,mouseenter, mouseleave
- 키보드 이벤트
keydown
: 모든 키를 누를 때keypress
: 문자 입력 시 (폐지)keyup
: 키에서 손을 뗄 때
- 포커스 이벤트
focus
,blur
(버블링 X)focusin
,focusout
(버블링 O)
- 폼 이벤트
submit
,reset
(form 요소 관련)
- 값 변경 이벤트
input
: 입력 중 발생change
: 포커스 해제 시 값 변경 인식
- DOM 뮤테이션 이벤트
DOMContentLoaded
: DOM 로딩 완료
- 뷰 이벤트
resize
: 창 크기 변경scroll
: 스크롤 발생
- 리소스 이벤트
load
: 모든 리소스 로딩 완료unload
,abort
,error
: 페이지 이탈, 로딩 실패 등
40.3 이벤트 핸들러 등록
- 이벤트 핸들러 어트리뷰트 방식
- HTML 속성으로 등록:
<button onclick="sayHi('Lee')">
- 문자열로 여러 문장 사용 가능
- HTML 속성으로 등록:
- 이벤트 핸들러 프로퍼티 방식
- JS에서
on이벤트명
프로퍼티에 함수 할당:element.onclick = () => {}
- 단 하나의 핸들러만 등록 가능 (이후 할당 시 덮어쓰기 됨)
- JS에서
- addEventListener 메서드 방식
addEventListener('click', handler, useCapture)
- 여러 핸들러 등록 가능, 순서대로 실행
useCapture
를 true로 설정하면 캡처링 단계에서 실행
40.4 이벤트 핸들러 제거
removeEventListener('이벤트명', 핸들러)
: 등록된 핸들러 제거- 익명 함수로 등록된 핸들러는 제거 불가 (참조가 없기 때문)
- 핸들러 내부에서 자신을 제거하려면
arguments.callee
사용 가능 (strict mode에선 금지) - 프로퍼티 방식은
element.onclick = null
로 제거
40.5 이벤트 객체
- 이벤트 발생 시 브라우저가 관련 정보를 담은 이벤트 객체를 생성
- 이벤트 핸들러의 첫 번째 인수로 자동 전달됨
- 이벤트 핸들러 어트리뷰트 방식에선 반드시
event
라는 이름으로 사용해야 전달 가능 - 이벤트 객체의 상속 구조
- 기본 구조:
Object → Event → [하위 이벤트 객체들]
- 대표 하위 객체:
MouseEvent
,KeyboardEvent
,FocusEvent
,InputEvent
등 - 생성자 함수로 직접 생성 가능:
new Event('click')
,new MouseEvent('click')
등
- 기본 구조:
- 이벤트 객체의 공통 프로퍼티
target
: 이벤트 발생 요소currentTarget
: 이벤트 핸들러가 바인딩된 요소- 대부분의 경우
target === currentTarget
- 마우스 정보 취득
MouseEvent
고유 프로퍼티- 위치:
clientX/Y
,screenX/Y
,pageX/Y
,offsetX/Y
- 키 상태:
altKey
,ctrlKey
,shiftKey
,button
- 위치:
- 마우스 드래그 구현 시
mousedown
,mousemove
,mouseup
조합 사용 transform: translate3d(...)
로 GPU 활용하여 성능 개선
- 키보드 정보 취득
KeyboardEvent
고유 프로퍼티- 키값:
key
,code
,keyCode
(deprecated) - 수정키 상태:
altKey
,ctrlKey
,shiftKey
,metaKey
- 키값:
- 엔터 키 입력 시 동작:
e.key === 'Enter'
로 판별 - 한글 입력 후
keyup
이벤트가 중복될 수 있음 ->keydown
사용 권장
40.6 이벤트 전파
- 이벤트 전파 단계
- 캡처링(capturing): window -> target까지 내려가는 단계
- 타깃(target): 이벤트 발생 요소에 도달한 시점
- 버블링(bubbling): target -> window 방향으로 올라가는 단계
- 등록 방식 별 이벤트 캐치 기능 단계
- 어트리뷰트 / 프로퍼티 방식: 타깃 + 버블링 단계만 캐치
addEventListener
: 기본은 버블링,true
전달 시 캡처링 캐치 가능
- 전파되지 않는 이벤트
- 버블링되지 않음:
focus
,blur
,mouseenter
,mouseleave
,load
,error
,abort
,unload
- 대체 가능 이벤트
focus
/blur
→focusin
/focusout
mouseenter
/mouseleave
->mouseover
/mouseout
- 버블링되지 않음:
40.7 이벤트 위임
- 여러 하위 요소 각각에 이벤트 핸들러를 등록하는 대신 상위 요소 하나에 이벤트 핸들러를 등록하여 하위 이벤트를 처리하는 방식
- 성능 최적화, 동적 요소 대응이 가능
event.target
: 이벤트 발생 원소 확인Element.prototype.matches(selector)
: 원하는 요소인지 필터링 가능event.currentTarget
: 항상 이벤트 핸들러가 바인딩된 요소(ul
등)event.target
: 실제 이벤트 발생 요소(li
등)
40.8 DOM 요소의 기본 동작 조작
- DOM 요소의 기본 동작 중단
event.preventDefault()
: 링크 이동, 체크박스 체크 등 기본 동작 차단<a>
의 이동 방지,<input type="checkbox">
상태 변경 방지
- 이벤트 전파 방지
event.stopPropagation()
: 이벤트 버블링 또는 캡처링 차단- 특정 버튼만 독립적으로 동작하고 상위 요소 이벤트 위임에 반응하지 않게 할 수 있음
40.9 이벤트 핸들러 내부의 this
- 이벤트 핸들러 어트리뷰트 방식
this
는window
(일반 함수 호출)onclick="handleClick(this)"
로 전달 가능
- 이벤트 핸들러 프로퍼티 방식과 addEventListener 메서드 방식
this === event.currentTarget
(이벤트 바인딩된 요소)
40.10 이벤트 핸들러에 인수 전달
- 직접 함수 호출 불가 -> 핸들러 내부에서 다른 함수 호출하며 인수 전달
- 커링 함수(함수를 반환하는 함수) 사용:
handler = param => e => {}
40.11 커스텀 이벤트
- 커스텀 이벤트 생성
- 생성자:
new CustomEvent(type, { detail })
,new MouseEvent
,new KeyboardEvent
등 bubbles
,cancelable
,detail
등의 옵션 지정 가능- 커스텀 이벤트는
isTrusted: false
(사용자 행위가 아닌 스크립트에 의해 발생)
- 생성자:
- 커스텀 이벤트 디스패치
dispatchEvent(event)
를 통해 이벤트 수동 발생 (동기 처리)
- 반드시 addEventListener 방식으로 핸들러 등록
- 어트리뷰트/프로퍼티 방식은
on<type>
속성이 없으므로 불가능
- 어트리뷰트/프로퍼티 방식은