웹 앱, 웹 사이트 만들 때 사용할 수 있는 모든 객체 유형
보통 JavaScript와 함께 사용
DOM 상속 구조
[EventTarget] ← [Node] ← [Element] ← [HTMLElement]
[EventTarget] ← [Node] ← [DocumentType] [CharacterData(Text)]
[EventTarget] ← [Window]
DOM 요소 추가
| Properties | ||
|---|---|---|
| textContent | Node.textContent = string |
모든 콘텐츠 (script, style) |
| innerHTML | Element.innerHTML = htmlString |
HTML,XML 마크업 → XSS 공격 위험 |
| innerText | HTMLElement.innerText = string |
hidden 요소 제외 → reflow발생 |
| Methods | ||
|---|---|---|
| appendChild | Node.appendChild(Node) |
하나의 Node 객체를 자식노드 맨 뒤에 추가 return 반환 |
| append | Element.append(Node, String) |
하나 이상의 Node 객체 또는 String 객체를 자식노드 맨 뒤에 추가 |
| prepend | Element.prepend(Node, String) |
하나 이상의 Node 객체 또는 String 객체를 자식노드 맨 앞에 추가 |
Shadow DOM 만들기
ShadowRoot
[EventTarget] ← [Node] ← [DocumentFragment] ← [ShadowRoot]
element.attachShadow({ mode: 'open' });- Shadow Host : attach한 DOM 요소
- Shadow Tree : Shadow DOM 내부 트리
- Shadow Root : Shadow Tree의 root node
host CSS
- 성능 향상을 위해 :host CSS 컨테이너 사용
constructor(){
super()
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `
<style>
:host{color:#000}
:host(.class){color:#000}
</style>
`
}닫힌 루트 {mode: 'close'}
- 사용 지양 (보안 기능이 아님)
사용자 정의 요소 (Custom Elements API)
캡슐화, CustomElementRegistry 객체
pupup-components.js
class myPopup extends HTMLElement{
connectedCallback(){
this.innerHTML = `<div>팝업!</div>`
}
}
customElements.define('my-popup', myPopup);
// Or 익명 클래스 (anonymous class)
customElements.define('my-popup', class extends HTMLElement {
connectedCallback(){
this.innerHTML = `<div>팝업!</div>`
}
});
// Or Shadow DOM 사용자 정의 요소
customElements.define('my-popup', class extends HTMLElement {
constructor(){
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `<div>팝업!</div>`
}
})index.html
<my-popup></my-popup>customElements.define() : 사용자 요소 정의
define(name, constructor, options) // CustomElementRegistry methodname사용자 정의 요소 이름
규칙: 소문자 시작, 하이픈 꼭 포함(HTML 요소와 구분하기 위함)constructor생성자 class 객체options선택사항{extends: "p"}
Constructor (생성자) : 인스턴스 객체 초기화
constructor(){
super();
}
// Or Shadow DOM 생성
constructor(){
super();
this.attachShadow({ mode: 'open' });
}- 직접적인 DOM 조작 금지
- 항상
super()호출 (부모 생성자 호출 후this사용 가능)super(): 상속 받은 부모 클래스(HTMLElement)의 생성자 호출super()필요한 경우- 내부 상태 초기화
- shadow DOM 생성 시
- 이벤트 핸들러 사전 바인딩 시
- 재 렌더링 방지용 flag (
this._initialized="flase")
커스텀 요소 수명 주기 (lifecycle callbacks)
- connectedCallback : DOM 첫 렌더, 요소가(
<my-popup>) DOM에 연결될 때마다 호출- constructor 사용 안할 시 명시하지 않아도 됨
- attributeChangedCallback : 속성 변경 시 변경된 부분만 업데이트
- disconnectedCallback : 요소가 DOM에 연결 해제 되었을 때마다 호출
userAgent
navigator.userAgent
- 브라우저와 운영체제 정보 문자열
- 최신 브라우저는 개인정보를 위해 단순화하여 신뢰도 낮음
- 표준화 되어있지 않기때문에 세밀한 필터 불가
- 디바이스 감지 정도에만 사용
const isMobile = /iPhone|iPad|iPod|Android|BlackBerry|Windows CE/i.test(navigator.userAgent)navigator.userAgentData
- UA 객체
- 최신 브라우저에서만 사용
window.localStorage
[EventTarget] ← [Window]
| Methods | |
|---|---|
localStorage.setItem(keyName, keyValue) |
string, array 불가 |
localStorage.getItem(keyName) |
키 값(string) 반환, 없으면 null |
localStorage.removeItem(keyName) |
키 값 제거 |
window.requestAnimationFrame() method
브라우저가 다음 화면을 그리기 직전 콜백 실행 (브라우저 주사율 기준 보통 60Hz)
setInterval 과 비교
requestAnimationFrame |
setInterval |
|
|---|---|---|
| 실행 타이밍 | 다음 프레임 직전 | 지정한 ms 무조건 실행 |
| 백그라운드 | 자동 일시정지 (효율적) | 계속 실행 (낭비) |
| 프레임 동기화 | 정확히 맞춤 (부드러움) | 어긋날 수 있음 |
| 중지 | cancelAnimationFrame(id) |
clearInterval(id) |
const reqAni = () => {
const currentLeft = parseFloat(~.style.left) || 0
~.style.left = currentLeft + 10 + 'px'
if (currentLeft < 300) {
requestAnimationFrame(reqAni)
// return 시에도 멈춤
}
}
reqAni()const setInt = setInterval(()=>{
const currentLeft = parseFloat(~.style.left) || 0;
~.style.left = currentLeft + 10 + 'px';
if(currentLeft > 300){
clearInterval(setInt);
}
}, 16) // 16ms씩 무조건 실행사이즈와 스크롤
Window Size
| Properties | |
|---|---|
window.innerWidth window.innerHeight |
브라우저 메뉴바, 툴바, 스크롤바 제외 |
window.outerWidth window.outerHeight |
브라우저 메뉴바, 툴바, 스크롤바 포함 |
Size
| Properties | |
|---|---|
Element.clientWidth Element.clientHeight |
Element + padding (스크롤 바 생길 시 제외) |
Element.scrollWidth Element.scrollHeight |
스크롤 영역 밖 모든 콘텐츠 Element + padding (스크롤 바 생길 시 제외) |
HTMLElement.offsetWidth HTMLElement.offsetHeight |
Element + padding + border (스크롤 바 생길 시 동일) |
Margin size
| Window Methods | |
|---|---|
HTMLElement.style.marginLeft |
인라인 스타일로 지정된 값(String) 예) 20px |
getComputedStyle(Element).marginLeft |
css 포함 적용된 스타일 값(String) |
Scroll
| Properties | |
|---|---|
window.scrollX window.scrollY === .pageXOffset .pageYOffset |
스크롤 된 픽셀 수 |
Element.scrollLeft Element.scrollTop |
Element 내부(overflow:auto) scroll 픽셀 수 get, set 설정(set) Element.scrollTop = number |
HTMLElement.offsetLeft HTMLElement.offsetTop |
부모 position 기준 상대 좌표 (부모에 position 없을 시 <body> 좌표 또는 <table> 좌표) |
| Methods | |
|---|---|
window(Element).scrollTo(x, y) .scrollTo({top:y, left:x, behavior: '...'}) === .scroll() |
해당 좌표로 스크롤 |
window(Element).scrollBy(x, y) .scrollBy({top:y, left:x, behavior: '...'}) |
현재 좌표 기준으로 해당 좌표만큼 스크롤 |
Element.getBoundingClientRect() |
Element 크기, 위치 정보를 담은 DOMRect 객체 반환 x / left, y / top, right, bottom width, height, : padding 더한 값 |
부모에 position 있어도 <body> Scroll 값(절대 값) 사용할 때:
window.scrollY + Element.getBoundingClientRect().top;
Cookie
key=value 와 option(path, expires) 문자열
set
function setCookie(name, value, setExpires) {
const numericDays = Number(setExpires) || 0;
const expireDate = new Date();
expireDate.setDate(expireDate.getDate() + numericDays);
document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; expires=${expireDate.toUTCString()}; path=/; SameSite=Lax; Secure`;
}
setCookie('cookieName', 'cookieValue', 7)-
encodeURIComponentdecodeURIComponent- .cookie 는 HTTP 헤더 통해 전달: Protocol 준수, 데이터로 인해 쿠키 문자열 형식(
=;,…) 파괴 방지
ex) name:user=NA=;ME;
- .cookie 는 HTTP 헤더 통해 전달: Protocol 준수, 데이터로 인해 쿠키 문자열 형식(
-
SameSite: 교차 사이트 요청SameSite=Strict;: 도메인 완전히 일치SameSite=Lax;: iframe, AJAX 호츨에는 전송하지 않음 (일반적)SameSite=None;: 도메인 달라도 무조건 전송, Secure 속성 설정되어야만 작동
-
Secure: HTTPS 연결에만 쿠키 전송
get
function getCookie(name){
const escapedName = encodeURIComponent(name).replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1');
const nameMatche = document.cookie.match(new RegExp(
"(?:^|; )" + escapedName + "=([^;]*)"
));
return nameMatche ? decodeURIComponent(nameMatche[1]) : null;
}$1: 첫 번째 그룹(...)에서 매치된 텍스트 그대로 치환
ex) * → /* (Escape)- escaped 이유: 정규 표현식 정확히(특수 기호 일반 문자열로 변경) 매칭
ex) name:user.name일 경우 (패턴.: 모든 문자 1개 매칭) →user_nameuser*name매칭
delete
function deleteCookie(name){
const initDate = "Thu, 01 Jan 1970 00:00:00 GMT"
document.cookie = `${encodeURIComponent(name)}=; expires=${initDate}; path=/; SameSite=Lax; Secure`
}- 유닉스 타임(Unix Epoch) 시작점
- setCookie 와 option 동일하게 지정
Geolocation API
현재 위치 가져오는 API (HTTPS에서만 사용 가능)
function succeess(coords) {
coords.latitude //위도
coords.longitude //경도
}
navigator.geolocation.getCurrentPosition(success, error, [options]);getAnimations()
요소에 현재 적용 중인 모든 애니메이션 Promise 객체 배열 반환
element.getAnimations().playbackRate: 재생 속도.finished: 완료 시.cancel(): 실행 중인 모든 애니메이션 종료
element.getAnimations().map(ani => ani.playbackRate = 0.5)JavaScript
JSON
| Methods | |
|---|---|
JSON.stringify() |
Object, array → JSON String |
JSON.parse() |
JSON String → Object, array |
Promise()
비동기 작업의 최종 완료 또는 실패 나타내는 객체
new Promise(executor)Promise State
Pending | Fulfilled | Rejected
생성
const myPromise = new Promise((resolve, reject) =>{
resolve(value)
//or
reject("에러")
})사용
myPromise
.then(data => data)
.catch(error => console.error(error))
.finally(()=> 작업종료)async function handlePromise(){
try{
const data = await myPromise;
}catch(error){
console.error(error)
}finally{
작업종료
}
}| Promise Array | 반환 시점 | 결과 |
|---|---|---|
| Promise.all() | 하나라도 실패 시 바로 reject | resolve 배열 또는 reject(첫 번째 reject) |
| Promise.allSettled() | 모든 Promise 처리된 후 | 상태 포함한 객체 배열 |
//Promise 중 reject 있을 때
//Promise.all(Promise array)
PromiseState: "rejected"
PromiseResult: 거부 사유
//Promise.allSettled(Promise array)
PromiseState: "fulfilled",
PromiseResult: [{status: 'fulfilled', value: Array...}, {status: 'rejected', reason: 거부 사유}]